diff --git a/SConstruct b/SConstruct index 0d4f12e50463..f4a504d5e261 100644 --- a/SConstruct +++ b/SConstruct @@ -130,7 +130,6 @@ env.__class__.use_windows_spawn_fix = methods.use_windows_spawn_fix env.__class__.add_shared_library = methods.add_shared_library env.__class__.add_library = methods.add_library -env.__class__.add_program = methods.add_program env.__class__.CommandNoCache = methods.CommandNoCache env.__class__.Run = methods.Run env.__class__.disable_warnings = methods.disable_warnings @@ -204,6 +203,15 @@ opts.Add(("accesskit_sdk_path", "Path to the AccessKit C SDK", "")) opts.Add(BoolVariable("sdl", "Enable the SDL3 input driver", True)) # Advanced options +opts.Add( + EnumVariable( + "library_type", + "Build library type", + "executable", + ("executable", "static_library", "shared_library"), + ) +) +opts.Add(BoolVariable("external_target", "Enable external target rendering", False)) opts.Add( BoolVariable( "dev_mode", "Alias for dev options: verbose=yes warnings=extra werror=yes tests=yes strict_checks=yes", False @@ -330,6 +338,18 @@ if env["import_env_vars"]: # Platform selection: validate input, and add options. +if env["external_target"]: + env.Append(CPPDEFINES=["EXTERNAL_TARGET_ENABLED"]) + +if env["library_type"] == "static_library": + env.Append(CPPDEFINES=["LIBGODOT_ENABLED"]) +elif env["library_type"] == "shared_library": + env.Append(CPPDEFINES=["LIBGODOT_ENABLED"]) + env.Append(CCFLAGS=["-fPIC"]) + env.Append(STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME=True) +else: + env.__class__.add_program = methods.add_program + if not env["platform"]: # Missing `platform` argument, try to detect platform automatically if ( diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index a9673cf79b33..264419e65db1 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -83,6 +83,11 @@ const PackedStringArray ProjectSettings::get_required_features() { // Returns the features supported by this build of Godot. Includes all required features. const PackedStringArray ProjectSettings::_get_supported_features() { PackedStringArray features = get_required_features(); + +#ifdef LIBGODOT_ENABLED + features.append("LibGodot"); +#endif + #ifdef MODULE_MONO_ENABLED features.append("C#"); #endif diff --git a/core/core_bind.cpp b/core/core_bind.cpp index f58556468ac2..2647e1dfc351 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -1696,6 +1696,8 @@ TypedArray ClassDB::class_get_method_list(const StringName &p_class, #else Dictionary dict; dict["name"] = E.name; + dict["is_static"] = E.is_static; + dict["hash"] = E.hash; ret.push_back(dict); #endif // DEBUG_ENABLED } @@ -2281,6 +2283,10 @@ EngineDebugger::~EngineDebugger() { ::EngineDebugger::unregister_message_capture(E.key); } captures.clear(); + + if (singleton == this) { + singleton = nullptr; + } } void EngineDebugger::_bind_methods() { diff --git a/core/core_bind.h b/core/core_bind.h index ee4054fd7c0e..f489346f47a4 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -86,6 +86,12 @@ class ResourceLoader : public Object { Vector list_directory(const String &p_directory); ResourceLoader() { singleton = this; } + + ~ResourceLoader() { + if (singleton == this) { + singleton = nullptr; + } + } }; class ResourceSaver : public Object { @@ -118,6 +124,12 @@ class ResourceSaver : public Object { ResourceUID::ID get_resource_id_for_path(const String &p_path, bool p_generate = false); ResourceSaver() { singleton = this; } + + ~ResourceSaver() { + if (singleton == this) { + singleton = nullptr; + } + } }; class Logger : public RefCounted { @@ -383,6 +395,12 @@ class Geometry2D : public Object { TypedArray bresenham_line(const Point2i &p_from, const Point2i &p_to); Geometry2D() { singleton = this; } + + ~Geometry2D() { + if (singleton == this) { + singleton = nullptr; + } + } }; class Geometry3D : public Object { @@ -414,6 +432,12 @@ class Geometry3D : public Object { Vector tetrahedralize_delaunay(const Vector &p_points); Geometry3D() { singleton = this; } + + ~Geometry3D() { + if (singleton == this) { + singleton = nullptr; + } + } }; class Marshalls : public Object { @@ -640,6 +664,12 @@ class Engine : public Object { #endif Engine() { singleton = this; } + + ~Engine() { + if (singleton == this) { + singleton = nullptr; + } + } }; class EngineDebugger : public Object { diff --git a/core/core_string_names.h b/core/core_string_names.h index 3a45152f17db..b396118cdf62 100644 --- a/core/core_string_names.h +++ b/core/core_string_names.h @@ -36,10 +36,16 @@ class CoreStringNames { inline static CoreStringNames *singleton = nullptr; public: - static void create() { singleton = memnew(CoreStringNames); } + static void create() { + if (singleton == nullptr) { + singleton = memnew(CoreStringNames); + } + } static void free() { +#ifndef LIBGODOT_ENABLED memdelete(singleton); singleton = nullptr; +#endif } _FORCE_INLINE_ static CoreStringNames *get_singleton() { return singleton; } diff --git a/core/extension/gdextension_function_loader.cpp b/core/extension/gdextension_function_loader.cpp new file mode 100644 index 000000000000..d3ff2f27cd66 --- /dev/null +++ b/core/extension/gdextension_function_loader.cpp @@ -0,0 +1,75 @@ +/**************************************************************************/ +/* gdextension_function_loader.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 "gdextension_function_loader.h" +#include "core/config/project_settings.h" +#include "gdextension.h" + +Error GDExtensionFunctionLoader::open_library(const String &p_path) { + ERR_FAIL_COND_V_MSG(!p_path.begins_with("libgodot://"), ERR_FILE_NOT_FOUND, "Function based GDExtensions should have a path starting with libgodot://"); + ERR_FAIL_COND_V_MSG(!initialization_function, ERR_DOES_NOT_EXIST, "Initialization function is required for function based GDExtensions."); + + library_path = p_path; + + return OK; +} + +Error GDExtensionFunctionLoader::initialize(GDExtensionInterfaceGetProcAddress p_get_proc_address, const Ref &p_extension, GDExtensionInitialization *r_initialization) { + ERR_FAIL_COND_V_MSG(!initialization_function, ERR_DOES_NOT_EXIST, "Initialization function is required for function based GDExtensions."); + GDExtensionBool ret = initialization_function(p_get_proc_address, p_extension.ptr(), r_initialization); + + if (ret) { + return OK; + } else { + ERR_PRINT("GDExtension initialization function for '" + library_path + "' returned an error."); + return FAILED; + } +} + +void GDExtensionFunctionLoader::close_library() { + initialization_function = nullptr; + library_path.clear(); +} + +bool GDExtensionFunctionLoader::is_library_open() const { + return !library_path.is_empty(); +} + +bool GDExtensionFunctionLoader::has_library_changed() const { + return false; +} + +bool GDExtensionFunctionLoader::library_exists() const { + return true; +} + +void GDExtensionFunctionLoader::set_initialization_function(GDExtensionInitializationFunction p_initialization_function) { + initialization_function = p_initialization_function; +} diff --git a/core/extension/gdextension_function_loader.h b/core/extension/gdextension_function_loader.h new file mode 100644 index 000000000000..dee26a045df7 --- /dev/null +++ b/core/extension/gdextension_function_loader.h @@ -0,0 +1,56 @@ +/**************************************************************************/ +/* gdextension_function_loader.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. */ +/**************************************************************************/ + +#pragma once + +#include "core/extension/gdextension_loader.h" +#include "core/os/shared_object.h" +#include + +class GDExtension; + +class GDExtensionFunctionLoader : public GDExtensionLoader { + friend class GDExtensionManager; + friend class GDExtension; + +private: + String library_path; + GDExtensionInitializationFunction initialization_function = nullptr; + +public: + Error open_library(const String &p_path) override; + Error initialize(GDExtensionInterfaceGetProcAddress p_get_proc_address, const Ref &p_extension, GDExtensionInitialization *r_initialization) override; + void close_library() override; + bool is_library_open() const override; + bool has_library_changed() const override; + bool library_exists() const override; + + void set_initialization_function(GDExtensionInitializationFunction initialization_function); +}; diff --git a/core/extension/gdextension_manager.cpp b/core/extension/gdextension_manager.cpp index a8b22997288b..6279e71125b1 100644 --- a/core/extension/gdextension_manager.cpp +++ b/core/extension/gdextension_manager.cpp @@ -30,6 +30,7 @@ #include "gdextension_manager.h" +#include "core/extension/gdextension_function_loader.h" #include "core/extension/gdextension_library_loader.h" #include "core/extension/gdextension_special_compat_hashes.h" #include "core/io/dir_access.h" @@ -114,7 +115,14 @@ GDExtensionManager::LoadStatus GDExtensionManager::load_extension(const String & Ref loader; loader.instantiate(); - return GDExtensionManager::get_singleton()->load_extension_with_loader(p_path, loader); + return load_extension_with_loader(p_path, loader); +} + +GDExtensionManager::LoadStatus GDExtensionManager::load_function_extension(const String &p_path, GDExtensionConstPtr p_init_func) { + Ref func_loader; + func_loader.instantiate(); + func_loader->set_initialization_function((GDExtensionInitializationFunction) * (p_init_func.data)); + return load_extension_with_loader(p_path, func_loader); } GDExtensionManager::LoadStatus GDExtensionManager::load_extension_with_loader(const String &p_path, const Ref &p_loader) { @@ -454,6 +462,7 @@ GDExtensionManager *GDExtensionManager::get_singleton() { void GDExtensionManager::_bind_methods() { ClassDB::bind_method(D_METHOD("load_extension", "path"), &GDExtensionManager::load_extension); + ClassDB::bind_method(D_METHOD("load_function_extension", "path", "init_func"), &GDExtensionManager::load_function_extension); ClassDB::bind_method(D_METHOD("reload_extension", "path"), &GDExtensionManager::reload_extension); ClassDB::bind_method(D_METHOD("unload_extension", "path"), &GDExtensionManager::unload_extension); ClassDB::bind_method(D_METHOD("is_extension_loaded", "path"), &GDExtensionManager::is_extension_loaded); diff --git a/core/extension/gdextension_manager.h b/core/extension/gdextension_manager.h index 93d9130a919e..d136fcdd4d6a 100644 --- a/core/extension/gdextension_manager.h +++ b/core/extension/gdextension_manager.h @@ -31,6 +31,9 @@ #pragma once #include "core/extension/gdextension.h" +#include "core/variant/native_ptr.h" + +GDVIRTUAL_NATIVE_PTR(GDExtensionInitializationFunction) class GDExtensionManager : public Object { GDCLASS(GDExtensionManager, Object); @@ -66,6 +69,7 @@ class GDExtensionManager : public Object { public: LoadStatus load_extension(const String &p_path); + LoadStatus load_function_extension(const String &p_path, GDExtensionConstPtr p_init_func); LoadStatus load_extension_with_loader(const String &p_path, const Ref &p_loader); LoadStatus reload_extension(const String &p_path); LoadStatus unload_extension(const String &p_path); diff --git a/core/extension/godot_instance.cpp b/core/extension/godot_instance.cpp new file mode 100644 index 000000000000..1808ced6d152 --- /dev/null +++ b/core/extension/godot_instance.cpp @@ -0,0 +1,186 @@ +/**************************************************************************/ +/* godot_instance.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 "godot_instance.h" +#include "core/extension/gdextension_manager.h" +#include "main/main.h" +#include "servers/display_server.h" + +#define GODOT_INSTANCE_LOG(...) print_line(__VA_ARGS__) + +TaskExecutor::TaskExecutor(InvokeCallbackFunction p_async_func, ExecutorData p_async_data, InvokeCallbackFunction p_sync_func, ExecutorData p_sync_data) { + async_func = p_async_func; + async_data = p_async_data; + sync_func = p_sync_func; + sync_data = p_sync_data; +} + +void TaskExecutor::sync(std::function p_callback) { + sync_func(&TaskExecutor::invokeCallback, new std::function(p_callback), sync_data); +} + +void TaskExecutor::async(std::function p_callback) { + async_func(&TaskExecutor::invokeCallback, new std::function(p_callback), async_data); +} + +void TaskExecutor::invokeCallback(void *p_callback) { + std::function *callback = (std::function *)p_callback; + (*callback)(); + delete callback; +} + +void GodotInstance::_bind_methods() { + ClassDB::bind_method(D_METHOD("start"), &GodotInstance::start); + ClassDB::bind_method(D_METHOD("is_started"), &GodotInstance::is_started); + ClassDB::bind_method(D_METHOD("iteration"), &GodotInstance::iteration); + ClassDB::bind_method(D_METHOD("focus_in"), &GodotInstance::focus_in); + ClassDB::bind_method(D_METHOD("focus_out"), &GodotInstance::focus_out); + ClassDB::bind_method(D_METHOD("pause"), &GodotInstance::pause); + ClassDB::bind_method(D_METHOD("resume"), &GodotInstance::resume); + ClassDB::bind_method(D_METHOD("execute", "callback", "async"), &GodotInstance::execute); +} + +GodotInstance::GodotInstance() { +} + +GodotInstance::~GodotInstance() { +} + +bool GodotInstance::initialize(GDExtensionInitializationFunction p_init_func, GodotInstanceCallbacks *p_callbacks) { + GODOT_INSTANCE_LOG("Godot Instance initialization"); + callbacks = p_callbacks; + GDExtensionManager *gdextension_manager = GDExtensionManager::get_singleton(); + GDExtensionConstPtr ptr((const GDExtensionInitializationFunction *)&p_init_func); + GDExtensionManager::LoadStatus status = gdextension_manager->load_function_extension("libgodot://main", ptr); + return status == GDExtensionManager::LoadStatus::LOAD_STATUS_OK; +} + +#define CALL_CB(cb) \ + if (callbacks) { \ + callbacks->cb(this); \ + } + +bool GodotInstance::start() { + GODOT_INSTANCE_LOG("GodotInstance::start()"); + CALL_CB(before_setup2); + Error err = Main::setup2(); + if (err != OK) { + return false; + } + CALL_CB(before_start); + started = Main::start() == EXIT_SUCCESS; + if (started) { + OS::get_singleton()->get_main_loop()->initialize(); + CALL_CB(after_start); + } + return started; +} + +bool GodotInstance::is_started() { + return started; +} + +bool GodotInstance::iteration() { + DisplayServer::get_singleton()->process_events(); + return Main::iteration(); +} + +void GodotInstance::stop() { + GODOT_INSTANCE_LOG("GodotInstance::stop()"); + if (started) { + OS::get_singleton()->get_main_loop()->finalize(); + } + started = false; +} + +void GodotInstance::focus_out() { + GODOT_INSTANCE_LOG("GodotInstance::focus_out()"); + if (started) { + if (OS::get_singleton()->get_main_loop()) { + OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT); + } + + callbacks->focus_out(this); + } +} + +void GodotInstance::focus_in() { + GODOT_INSTANCE_LOG("GodotInstance::focus_in()"); + if (started) { + if (OS::get_singleton()->get_main_loop()) { + OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_IN); + } + callbacks->focus_in(this); + } +} + +void GodotInstance::pause() { + GODOT_INSTANCE_LOG("GodotInstance::pause()"); + if (started) { + if (OS::get_singleton()->get_main_loop()) { + OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_PAUSED); + } + callbacks->pause(this); + } +} + +void GodotInstance::resume() { + GODOT_INSTANCE_LOG("GodotInstance::resume()"); + if (started) { + callbacks->resume(this); + if (OS::get_singleton()->get_main_loop()) { + OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_RESUMED); + } + } +} + +void GodotInstance::set_executor(TaskExecutor *p_executor) { + executor = p_executor; +} + +TaskExecutor *GodotInstance::get_executor() { + return executor; +} + +void GodotInstance::execute(Callable p_callback, bool p_async) { + if (executor == nullptr) { + p_callback.call(); + return; + } + if (p_async) { + executor->async([p_callback]() { + p_callback.call(); + }); + } else { + executor->sync([p_callback]() { + p_callback.call(); + }); + } +} diff --git a/core/extension/godot_instance.h b/core/extension/godot_instance.h new file mode 100644 index 000000000000..63c8ccde4cb6 --- /dev/null +++ b/core/extension/godot_instance.h @@ -0,0 +1,99 @@ +/**************************************************************************/ +/* godot_instance.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. */ +/**************************************************************************/ + +#pragma once + +#include "core/extension/gdextension_interface.h" +#include "core/object/class_db.h" +#include "core/object/object.h" + +#include + +typedef void *CallbackData; +typedef void *ExecutorData; +typedef void (*InvokeCallback)(CallbackData p_data); +typedef void (*InvokeCallbackFunction)(InvokeCallback p_callback, CallbackData p_callback_data, ExecutorData p_executor_data); + +class GodotInstance; +class GodotInstanceCallbacks { +public: + virtual void before_setup2(GodotInstance *p_instance) {} + virtual void before_start(GodotInstance *p_instance) {} + virtual void after_start(GodotInstance *p_instance) {} + virtual void focus_out(GodotInstance *p_instance) {} + virtual void focus_in(GodotInstance *p_instance) {} + virtual void pause(GodotInstance *p_instance) {} + virtual void resume(GodotInstance *p_instance) {} +}; + +class TaskExecutor { + InvokeCallbackFunction async_func; + ExecutorData async_data; + InvokeCallbackFunction sync_func; + ExecutorData sync_data; + +public: + TaskExecutor(InvokeCallbackFunction p_async_func, ExecutorData p_async_data, InvokeCallbackFunction p_sync_func, ExecutorData p_sync_data); + void sync(std::function p_callback); + void async(std::function p_callback); + + static void invokeCallback(void *p_callback); +}; + +class GodotInstance : public Object { + GDCLASS(GodotInstance, Object); + + static void _bind_methods(); + + bool started = false; + + GodotInstanceCallbacks *callbacks = nullptr; + TaskExecutor *executor = nullptr; + +public: + GodotInstance(); + ~GodotInstance(); + + bool initialize(GDExtensionInitializationFunction p_init_func, GodotInstanceCallbacks *p_callbacks = nullptr); + + bool start(); + bool is_started(); + bool iteration(); + void stop(); + + void focus_out(); + void focus_in(); + void pause(); + void resume(); + + void set_executor(TaskExecutor *p_executor); + TaskExecutor *get_executor(); + void execute(Callable p_callback, bool p_async); +}; diff --git a/core/extension/libgodot.h b/core/extension/libgodot.h new file mode 100644 index 000000000000..c8639ac6492c --- /dev/null +++ b/core/extension/libgodot.h @@ -0,0 +1,82 @@ +/**************************************************************************/ +/* libgodot.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. */ +/**************************************************************************/ + +#pragma once + +#include "gdextension_interface.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// Export macros for DLL visibility +#if defined(_MSC_VER) || defined(__MINGW32__) +#define LIBGODOT_API __declspec(dllexport) +#elif defined(__GNUC__) || defined(__clang__) +#define LIBGODOT_API __attribute__((visibility("default"))) +#endif // if defined(_MSC_VER) + +typedef void *CallbackData; +typedef void *ExecutorData; +typedef void (*InvokeCallback)(CallbackData p_data); +typedef void (*InvokeCallbackFunction)(InvokeCallback p_callback, CallbackData p_callback_data, ExecutorData p_executor_data); +typedef void *LogCallbackData; +typedef void (*LogCallbackFunction)(LogCallbackData p_data, const char *p_log_message, bool p_err); + +/** + * @name libgodot_create_godot_instance + * @since 4.4 + * + * Creates a new Godot instance. + * + * @param p_argc The number of command line arguments. + * @param p_argv The C-style array of command line arguments. + * @param p_init_func GDExtension initialization function of the host application. + * @param p_log_func Initialization log function, called with log message c string. + * + * @return A pointer to created \ref GodotInstance GDExtension object or nullptr if there was an error. + */ +LIBGODOT_API GDExtensionObjectPtr libgodot_create_godot_instance(int p_argc, char *p_argv[], GDExtensionInitializationFunction p_init_func, InvokeCallbackFunction p_async_func, ExecutorData p_async_data, InvokeCallbackFunction p_sync_func, ExecutorData p_sync_data, LogCallbackFunction p_log_func, LogCallbackData p_log_data, void *p_platform_data); + +/** + * @name libgodot_destroy_godot_instance + * @since 4.4 + * + * Destroys an existing Godot instance. + * + * @param p_godot_instance The reference to the GodotInstance object to destroy. + * + */ +LIBGODOT_API void libgodot_destroy_godot_instance(GDExtensionObjectPtr p_godot_instance); + +#ifdef __cplusplus +} +#endif diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp index 33bceee52d99..0fa7537f397d 100644 --- a/core/io/file_access_zip.cpp +++ b/core/io/file_access_zip.cpp @@ -227,6 +227,7 @@ ZipArchive::ZipArchive() { ZipArchive::~ZipArchive() { packages.clear(); + instance = nullptr; } Error FileAccessZip::open_internal(const String &p_path, int p_mode_flags) { diff --git a/core/io/ip.cpp b/core/io/ip.cpp index 94256a7b5726..e5a75b3407e0 100644 --- a/core/io/ip.cpp +++ b/core/io/ip.cpp @@ -345,6 +345,7 @@ IP::IP() { } IP::~IP() { + singleton = nullptr; resolver->thread_abort.set(); resolver->sem.post(); resolver->thread.wait_to_finish(); diff --git a/core/io/libgodot_logger.cpp b/core/io/libgodot_logger.cpp new file mode 100644 index 000000000000..64f319d9afe1 --- /dev/null +++ b/core/io/libgodot_logger.cpp @@ -0,0 +1,117 @@ +/**************************************************************************/ +/* libgodot_logger.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. */ +/**************************************************************************/ + +#ifdef LIBGODOT_ENABLED + +#include "libgodot_logger.h" + +void LibGodotLogger::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, const Vector> &p_script_backtraces) { + if (!should_log(true)) { + return; + } + + const char *err_details; + if (p_rationale && p_rationale[0]) { + err_details = p_rationale; + } else { + err_details = p_code; + } + + const char *err_type = "ERROR"; + + switch (p_type) { + case ERR_WARNING: { + err_type = "WARNING"; + } break; + case ERR_SCRIPT: { + err_type = "SCRIPT ERROR"; + } break; + case ERR_SHADER: { + err_type = "SHADER ERROR"; + } break; + case ERR_ERROR: + default: { + err_type = "ERROR"; + } break; + } + + logf_error("%s: %s\n at: %s (%s:%i)\n", err_type, err_details, p_function, p_file, p_line); + + for (const Ref &backtrace : p_script_backtraces) { + if (!backtrace->is_empty()) { + logf_error("%s\n", backtrace->format(3).utf8().get_data()); + } + } +} + +void LibGodotLogger::logv(const char *p_format, va_list p_list, bool p_err) { + if (!should_log(p_err)) { + return; + } + + const int static_buffer_size = 1024; + char static_buf[static_buffer_size]; + char *buf = static_buf; + va_list list_copy; + va_copy(list_copy, p_list); + int len = vsnprintf(buf, static_buffer_size, p_format, p_list); + if (len >= static_buffer_size) { + buf = (char *)memalloc(len + 1); + len = vsnprintf(buf, len + 1, p_format, list_copy); + } + va_end(list_copy); + + String str_buf = String::utf8(buf, len); + if (len >= static_buffer_size) { + memfree(buf); + } + + forward_log(str_buf, p_err); +} + +void LibGodotLogger::forward_log(const String &p_msg, bool p_err) { + if (log_func == nullptr) { + return; + } + + CharString cstr_buf = p_msg.utf8(); + if (cstr_buf.length() == 0) { + return; + } + + log_func(log_data, cstr_buf.get_data(), p_err); +} + +void LibGodotLogger::set_callback_function(LogCallbackFunction p_log_func, LogCallbackData p_log_data) { + log_func = p_log_func; + log_data = p_log_data; +} + +#endif // LIBGODOT_ENABLED diff --git a/core/io/libgodot_logger.h b/core/io/libgodot_logger.h new file mode 100644 index 000000000000..c8fc94eeb02c --- /dev/null +++ b/core/io/libgodot_logger.h @@ -0,0 +1,51 @@ +/**************************************************************************/ +/* libgodot_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. */ +/**************************************************************************/ + +#pragma once + +#ifdef LIBGODOT_ENABLED + +#include "core/extension/libgodot.h" +#include "core/io/logger.h" + +class LibGodotLogger : public Logger { +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, const Vector> &p_script_backtraces = {}) override; + virtual void logv(const char *p_format, va_list p_list, bool p_err) _PRINTF_FORMAT_ATTRIBUTE_2_0 override; + + void set_callback_function(LogCallbackFunction p_log_func, LogCallbackData p_log_data); + +private: + void forward_log(const String &p_msg, bool p_err); + LogCallbackFunction log_func = nullptr; + LogCallbackData log_data = nullptr; +}; + +#endif // LIBGODOT_ENABLED diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index 7ce92989f7f7..e76db0d37782 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -2542,3 +2542,9 @@ void ResourceFormatSaverBinary::get_recognized_extensions(const Ref &p ResourceFormatSaverBinary::ResourceFormatSaverBinary() { singleton = this; } + +ResourceFormatSaverBinary::~ResourceFormatSaverBinary() { + if (singleton == this) { + singleton = nullptr; + } +} diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h index f4e845ef6d4b..628728914c77 100644 --- a/core/io/resource_format_binary.h +++ b/core/io/resource_format_binary.h @@ -187,4 +187,5 @@ class ResourceFormatSaverBinary : public ResourceFormatSaver { virtual void get_recognized_extensions(const Ref &p_resource, List *p_extensions) const override; ResourceFormatSaverBinary(); + ~ResourceFormatSaverBinary(); }; diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp index fc36e5e131b6..8d6c4ceaa3e2 100644 --- a/core/io/resource_importer.cpp +++ b/core/io/resource_importer.cpp @@ -566,6 +566,12 @@ ResourceFormatImporter::ResourceFormatImporter() { singleton = this; } +ResourceFormatImporter::~ResourceFormatImporter() { + if (singleton == this) { + singleton = nullptr; + } +} + ////////////// void ResourceImporter::get_build_dependencies(const String &p_path, HashSet *r_dependencies) { diff --git a/core/io/resource_importer.h b/core/io/resource_importer.h index 4ab2b0f951da..c65d7f643d78 100644 --- a/core/io/resource_importer.h +++ b/core/io/resource_importer.h @@ -102,6 +102,7 @@ class ResourceFormatImporter : public ResourceFormatLoader { Error get_resource_import_info(const String &p_path, StringName &r_type, ResourceUID::ID &r_uid, String &r_import_group_file) const; ResourceFormatImporter(); + ~ResourceFormatImporter(); }; class ResourceImporter : public RefCounted { diff --git a/core/io/resource_uid.cpp b/core/io/resource_uid.cpp index 7b3fd0948dfa..9a494cacce89 100644 --- a/core/io/resource_uid.cpp +++ b/core/io/resource_uid.cpp @@ -379,4 +379,7 @@ ResourceUID::~ResourceUID() { if (crypto != nullptr) { memdelete((CryptoCore::RandomGenerator *)crypto); } + if (singleton == this) { + singleton = nullptr; + } } diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp index e8c82aae7af5..7d01917a4333 100644 --- a/core/object/class_db.cpp +++ b/core/object/class_db.cpp @@ -840,7 +840,7 @@ bool ClassDB::is_virtual(const StringName &p_class) { return scr.is_valid() && scr->is_valid() && scr->is_abstract(); } -void ClassDB::_add_class(const StringName &p_class, const StringName &p_inherits) { +void ClassDB::_add_class(const StringName &p_class, const StringName &p_inherits, void (*p_deinit_func)(bool deinit)) { Locker::Lock lock(Locker::STATE_WRITE); const StringName &name = p_class; @@ -850,6 +850,7 @@ void ClassDB::_add_class(const StringName &p_class, const StringName &p_inherits classes[name] = ClassInfo(); ClassInfo &ti = classes[name]; ti.name = name; + ti.deinit_func = p_deinit_func; ti.inherits = p_inherits; ti.api = current_api; @@ -866,6 +867,8 @@ static MethodInfo info_from_bind(MethodBind *p_method) { MethodInfo minfo; minfo.name = p_method->get_name(); minfo.id = p_method->get_method_id(); + minfo.is_static = p_method->is_static(); + minfo.hash = p_method->get_hash(); for (int i = 0; i < p_method->get_argument_count(); i++) { minfo.arguments.push_back(p_method->get_argument_info(i)); @@ -2390,6 +2393,9 @@ void ClassDB::cleanup() { memdelete(F.value[i]); } } + if (ti.deinit_func) { + ti.deinit_func(true); + } } classes.clear(); diff --git a/core/object/class_db.h b/core/object/class_db.h index d82a6850cc82..9105223e6883 100644 --- a/core/object/class_db.h +++ b/core/object/class_db.h @@ -163,7 +163,7 @@ class ClassDB { bool is_runtime = false; // The bool argument indicates the need to postinitialize. Object *(*creation_func)(bool) = nullptr; - + void (*deinit_func)(bool deinit) = nullptr; ClassInfo() {} ~ClassInfo() {} }; @@ -219,7 +219,7 @@ class ClassDB { static APIType current_api; static HashMap api_hashes_cache; - static void _add_class(const StringName &p_class, const StringName &p_inherits); + static void _add_class(const StringName &p_class, const StringName &p_inherits, void (*p_deinit_func)(bool deinit) = nullptr); static HashMap> default_values; static HashSet default_values_cached; diff --git a/core/object/object.cpp b/core/object/object.cpp index 265c2f120d97..2e5a34da47af 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -144,6 +144,8 @@ TypedArray convert_property_list(const Vector &p_vecto MethodInfo::operator Dictionary() const { Dictionary d; d["name"] = name; + d["is_static"] = is_static; + d["hash"] = hash; d["args"] = convert_property_list(arguments); Array da; for (int i = 0; i < default_arguments.size(); i++) { @@ -1666,12 +1668,16 @@ Variant Object::_get_indexed_bind(const NodePath &p_name) const { return get_indexed(p_name.get_as_property_path().get_subnames()); } -void Object::initialize_class() { +void Object::initialize_class(bool deinit) { static bool initialized = false; + if (deinit) { + initialized = false; + return; + } if (initialized) { return; } - _add_class_to_classdb(get_class_static(), StringName()); + _add_class_to_classdb(get_class_static(), StringName(), Object::initialize_class); _bind_methods(); _bind_compatibility_methods(); initialized = true; @@ -1747,8 +1753,8 @@ void Object::_clear_internal_resource_paths(const Variant &p_var) { } } -void Object::_add_class_to_classdb(const StringName &p_class, const StringName &p_inherits) { - ClassDB::_add_class(p_class, p_inherits); +void Object::_add_class_to_classdb(const StringName &p_class, const StringName &p_inherits, void (*p_deinit_func)(bool deinit)) { + ClassDB::_add_class(p_class, p_inherits, p_deinit_func); } void Object::_get_property_list_from_classdb(const StringName &p_class, List *p_list, bool p_no_inheritance, const Object *p_validator) { @@ -2504,7 +2510,12 @@ void ObjectDB::remove_instance(Object *p_object) { } void ObjectDB::setup() { - //nothing to do now + spin_lock.lock(); + slot_count = 0; + slot_max = 0; + object_slots = nullptr; + validator_counter = 0; + spin_lock.unlock(); } void ObjectDB::cleanup() { @@ -2545,7 +2556,10 @@ void ObjectDB::cleanup() { if (object_slots) { memfree(object_slots); + object_slots = nullptr; } - + slot_count = 0; + slot_max = 0; + validator_counter = 0; spin_lock.unlock(); } diff --git a/core/object/object.h b/core/object/object.h index 0f9812439167..8690f097e046 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -243,6 +243,8 @@ struct MethodInfo { Vector default_arguments; int return_val_metadata = 0; Vector arguments_metadata; + bool is_static = false; + uint64_t hash = 0; int get_argument_meta(int p_arg) const { ERR_FAIL_COND_V(p_arg < -1 || p_arg > arguments.size(), 0); @@ -267,7 +269,8 @@ struct MethodInfo { name(*reinterpret_cast(pinfo.name)), return_val(PropertyInfo(pinfo.return_value)), flags(pinfo.flags), - id(pinfo.id) { + id(pinfo.id), + is_static(pinfo.flags & GDEXTENSION_METHOD_FLAG_STATIC) { for (uint32_t i = 0; i < pinfo.argument_count; i++) { arguments.push_back(PropertyInfo(pinfo.arguments[i])); } @@ -520,13 +523,17 @@ protected: } \ \ public: \ - static void initialize_class() { \ + static void initialize_class(bool deinit = false) { \ static bool initialized = false; \ + if (deinit) { \ + initialized = false; \ + return; \ + } \ if (initialized) { \ return; \ } \ m_inherits::initialize_class(); \ - _add_class_to_classdb(get_class_static(), super_type::get_class_static()); \ + _add_class_to_classdb(get_class_static(), super_type::get_class_static(), m_class::initialize_class); \ if (m_class::_get_bind_methods() != m_inherits::_get_bind_methods()) { \ _bind_methods(); \ } \ @@ -760,7 +767,7 @@ class Object { friend class ClassDB; friend class PlaceholderExtensionInstance; - static void _add_class_to_classdb(const StringName &p_class, const StringName &p_inherits); + static void _add_class_to_classdb(const StringName &p_class, const StringName &p_inherits, void (*p_deinit_func)(bool deinit) = nullptr); static void _get_property_list_from_classdb(const StringName &p_class, List *p_list, bool p_no_inheritance, const Object *p_validator); bool _disconnect(const StringName &p_signal, const Callable &p_callable, bool p_force = false); @@ -777,7 +784,8 @@ class Object { #endif public: // Should be protected, but bug in clang++. - static void initialize_class(); + static void initialize_class(bool deinit = false); + _FORCE_INLINE_ static void register_custom_data_to_otdb() {} public: diff --git a/core/os/midi_driver.cpp b/core/os/midi_driver.cpp index 6c748b149800..9791ad005c3a 100644 --- a/core/os/midi_driver.cpp +++ b/core/os/midi_driver.cpp @@ -42,6 +42,12 @@ MIDIDriver::MIDIDriver() { singleton = this; } +MIDIDriver::~MIDIDriver() { + if (singleton == this) { + singleton = nullptr; + } +} + MIDIDriver::MessageCategory MIDIDriver::Parser::category(uint8_t p_midi_fragment) { if (p_midi_fragment >= 0xf8) { return MessageCategory::RealTime; diff --git a/core/os/midi_driver.h b/core/os/midi_driver.h index 9ac37147a50f..733517e800ee 100644 --- a/core/os/midi_driver.h +++ b/core/os/midi_driver.h @@ -102,7 +102,7 @@ class MIDIDriver { static MIDIDriver *get_singleton(); MIDIDriver(); - virtual ~MIDIDriver() = default; + virtual ~MIDIDriver(); virtual Error open() = 0; virtual void close() = 0; diff --git a/core/os/os.h b/core/os/os.h index bbd1571738ed..559bf1a53dd5 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -110,8 +110,6 @@ class OS { bool _separate_thread_render = false; bool _silent_crash_handler = false; - // Functions used by Main to initialize/deinitialize the OS. - virtual void initialize() = 0; virtual void initialize_joypads() = 0; diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp index 6db6979e1edb..8ebb9a91d03b 100644 --- a/core/register_core_types.cpp +++ b/core/register_core_types.cpp @@ -39,6 +39,7 @@ #include "core/debugger/engine_profiler.h" #include "core/extension/gdextension.h" #include "core/extension/gdextension_manager.h" +#include "core/extension/godot_instance.h" #include "core/input/input.h" #include "core/input/input_map.h" #include "core/input/shortcut.h" @@ -282,6 +283,8 @@ void register_core_types() { GDREGISTER_CLASS(GDExtension); + GDREGISTER_ABSTRACT_CLASS(GodotInstance); + GDREGISTER_ABSTRACT_CLASS(GDExtensionManager); GDREGISTER_ABSTRACT_CLASS(ResourceUID); diff --git a/core/string/string_name.cpp b/core/string/string_name.cpp index 00a79d4da21b..2733f255b362 100644 --- a/core/string/string_name.cpp +++ b/core/string/string_name.cpp @@ -45,14 +45,16 @@ struct StringName::Table { }; void StringName::setup() { - ERR_FAIL_COND(configured); - for (uint32_t i = 0; i < Table::TABLE_LEN; i++) { - Table::table[i] = nullptr; + if (!configured) { + for (uint32_t i = 0; i < Table::TABLE_LEN; i++) { + Table::table[i] = nullptr; + } + configured = true; } - configured = true; } void StringName::cleanup() { +#ifndef LIBGODOT_ENABLED MutexLock lock(Table::mutex); #ifdef DEBUG_ENABLED @@ -104,6 +106,7 @@ void StringName::cleanup() { print_verbose(vformat("StringName: %d unclaimed string names at exit.", lost_strings)); } configured = false; +#endif } void StringName::unref() { diff --git a/core/string/string_name.h b/core/string/string_name.h index bcb640742788..d20b16270c79 100644 --- a/core/string/string_name.h +++ b/core/string/string_name.h @@ -180,6 +180,12 @@ class [[nodiscard]] StringName { #endif ~StringName() { if (likely(configured) && _data) { //only free if configured +#ifdef LIBGODOT_ENABLED + // LibGodot does not clean up StringNames on destroy_godot_instance, so we need to explicitly avoid calling unref() at static StringName destruction + if (_data->static_count.get() > 0) { + return; + } +#endif unref(); } } diff --git a/core/string/translation_server.cpp b/core/string/translation_server.cpp index ea9c103e4308..9c210bea2ea5 100644 --- a/core/string/translation_server.cpp +++ b/core/string/translation_server.cpp @@ -629,3 +629,9 @@ TranslationServer::TranslationServer() { doc_domain = get_or_add_domain("godot.documentation"); init_locale_info(); } + +TranslationServer::~TranslationServer() { + if (singleton == this) { + singleton = nullptr; + } +} diff --git a/core/string/translation_server.h b/core/string/translation_server.h index 48632953ce5f..5ed6ce4528cd 100644 --- a/core/string/translation_server.h +++ b/core/string/translation_server.h @@ -154,4 +154,5 @@ class TranslationServer : public Object { #endif // TOOLS_ENABLED TranslationServer(); + ~TranslationServer(); }; diff --git a/core/variant/native_ptr.h b/core/variant/native_ptr.h index e97bee035473..a0715e28cd93 100644 --- a/core/variant/native_ptr.h +++ b/core/variant/native_ptr.h @@ -31,6 +31,7 @@ #pragma once #include "core/math/audio_frame.h" +#include "core/variant/binder_common.h" #include "core/variant/method_ptrcall.h" #include "core/variant/type_info.h" diff --git a/drivers/SCsub b/drivers/SCsub index a5a5e6d8de65..da35420fc550 100644 --- a/drivers/SCsub +++ b/drivers/SCsub @@ -43,6 +43,8 @@ if env["platform"] in ["macos"]: SConscript("winmidi/SCsub") # Graphics drivers +if env["platform"] == "ios" or env["platform"] == "macos": + SConscript("apple/SCsub") if env["vulkan"]: SConscript("vulkan/SCsub") if env["d3d12"]: diff --git a/platform/macos/rendering_context_driver_vulkan_macos.h b/drivers/apple/rendering_context_driver_vulkan_apple.h similarity index 89% rename from platform/macos/rendering_context_driver_vulkan_macos.h rename to drivers/apple/rendering_context_driver_vulkan_apple.h index a91ae3537e8f..97341d6f184e 100644 --- a/platform/macos/rendering_context_driver_vulkan_macos.h +++ b/drivers/apple/rendering_context_driver_vulkan_apple.h @@ -1,5 +1,5 @@ /**************************************************************************/ -/* rendering_context_driver_vulkan_macos.h */ +/* rendering_context_driver_vulkan_apple.h */ /**************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -36,20 +36,20 @@ #import -class RenderingContextDriverVulkanMacOS : public RenderingContextDriverVulkan { +class RenderingContextDriverVulkanApple : public RenderingContextDriverVulkan { private: virtual const char *_get_platform_surface_extension() const override final; protected: - SurfaceID surface_create(const void *p_platform_data) override final; + virtual SurfaceID surface_create(Ref p_native_surface) override final; public: struct WindowPlatformData { CAMetalLayer *const *layer_ptr; }; - RenderingContextDriverVulkanMacOS(); - ~RenderingContextDriverVulkanMacOS(); + RenderingContextDriverVulkanApple(); + ~RenderingContextDriverVulkanApple(); }; #endif // VULKAN_ENABLED diff --git a/drivers/apple_embedded/rendering_context_driver_vulkan_apple_embedded.mm b/drivers/apple/rendering_context_driver_vulkan_apple.mm similarity index 70% rename from drivers/apple_embedded/rendering_context_driver_vulkan_apple_embedded.mm rename to drivers/apple/rendering_context_driver_vulkan_apple.mm index f25931377663..ff3c6132da63 100644 --- a/drivers/apple_embedded/rendering_context_driver_vulkan_apple_embedded.mm +++ b/drivers/apple/rendering_context_driver_vulkan_apple.mm @@ -1,5 +1,5 @@ /**************************************************************************/ -/* rendering_context_driver_vulkan_apple_embedded.mm */ +/* rendering_context_driver_vulkan_apple.mm */ /**************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,42 +28,44 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#import "rendering_context_driver_vulkan_apple_embedded.h" +#import "rendering_context_driver_vulkan_apple.h" +#include "drivers/apple/rendering_native_surface_apple.h" +#ifdef __APPLE__ #ifdef VULKAN_ENABLED -#ifdef USE_VOLK -#include -#else -#include -#endif +#include "drivers/vulkan/godot_vulkan.h" +#include "drivers/vulkan/rendering_native_surface_vulkan.h" -const char *RenderingContextDriverVulkanAppleEmbedded::_get_platform_surface_extension() const { +const char *RenderingContextDriverVulkanApple::_get_platform_surface_extension() const { return VK_EXT_METAL_SURFACE_EXTENSION_NAME; } -RenderingContextDriver::SurfaceID RenderingContextDriverVulkanAppleEmbedded::surface_create(const void *p_platform_data) { - const WindowPlatformData *wpd = (const WindowPlatformData *)(p_platform_data); +RenderingContextDriver::SurfaceID RenderingContextDriverVulkanApple::surface_create(Ref p_native_surface) { + Ref apple_native_surface = Object::cast_to(*p_native_surface); + ERR_FAIL_COND_V(apple_native_surface.is_null(), SurfaceID()); VkMetalSurfaceCreateInfoEXT create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT; - create_info.pLayer = *wpd->layer_ptr; + create_info.pLayer = (__bridge CAMetalLayer *)(void *)apple_native_surface->get_layer(); VkSurfaceKHR vk_surface = VK_NULL_HANDLE; VkResult err = vkCreateMetalSurfaceEXT(instance_get(), &create_info, get_allocation_callbacks(VK_OBJECT_TYPE_SURFACE_KHR), &vk_surface); ERR_FAIL_COND_V(err != VK_SUCCESS, SurfaceID()); - Surface *surface = memnew(Surface); - surface->vk_surface = vk_surface; - return SurfaceID(surface); + Ref vulkan_native_surface = RenderingNativeSurfaceVulkan::create(vk_surface); + RenderingContextDriver::SurfaceID result = RenderingContextDriverVulkan::surface_create(vulkan_native_surface); + + return result; } -RenderingContextDriverVulkanAppleEmbedded::RenderingContextDriverVulkanAppleEmbedded() { +RenderingContextDriverVulkanApple::RenderingContextDriverVulkanApple() { // Does nothing. } -RenderingContextDriverVulkanAppleEmbedded::~RenderingContextDriverVulkanAppleEmbedded() { +RenderingContextDriverVulkanApple::~RenderingContextDriverVulkanApple() { // Does nothing. } #endif // VULKAN_ENABLED +#endif // __APPLE__ diff --git a/drivers/apple/rendering_native_surface_apple.h b/drivers/apple/rendering_native_surface_apple.h new file mode 100644 index 000000000000..4c30a0847501 --- /dev/null +++ b/drivers/apple/rendering_native_surface_apple.h @@ -0,0 +1,59 @@ +/**************************************************************************/ +/* rendering_native_surface_apple.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. */ +/**************************************************************************/ + +#pragma once + +#include "core/variant/native_ptr.h" +#include "servers/rendering/rendering_native_surface.h" + +class RenderingNativeSurfaceApple : public RenderingNativeSurface { + GDCLASS(RenderingNativeSurfaceApple, RenderingNativeSurface); + +public: + // TODO: Remove workaround when SwiftGodot starts to support const void * arguments. + static Ref create_api(/* GDExtensionConstPtr */ uint64_t p_layer); + + static Ref create(void *p_layer); + + uint64_t get_layer(); + + RenderingContextDriver *create_rendering_context(const String &p_driver_name) override; + GLManager *create_gl_manager(const String &p_driver_name) override; + + void *get_native_id() const override; + + RenderingNativeSurfaceApple(); + ~RenderingNativeSurfaceApple(); + +private: + static void _bind_methods(); + + void *layer = nullptr; +}; diff --git a/drivers/apple/rendering_native_surface_apple.mm b/drivers/apple/rendering_native_surface_apple.mm new file mode 100644 index 000000000000..620012612370 --- /dev/null +++ b/drivers/apple/rendering_native_surface_apple.mm @@ -0,0 +1,333 @@ +/**************************************************************************/ +/* rendering_native_surface_apple.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 "rendering_native_surface_apple.h" +#include "drivers/gles3/storage/texture_storage.h" +#include "drivers/metal/rendering_context_driver_metal.h" +#include "servers/rendering/gl_manager.h" + +#import "rendering_context_driver_vulkan_apple.h" + +#import + +#if defined(GLES3_ENABLED) +#import + +#if defined(IOS_ENABLED) +#import +#import +#import +#import +#endif + +struct WindowData { + GLint backingWidth; + GLint backingHeight; + GLuint viewRenderbuffer, viewFramebuffer; + GLuint depthRenderbuffer; +#if defined(IOS_ENABLED) + CAEAGLLayer *layer; +#endif +#if defined(MACOS_ENABLED) + CAOpenGLLayer *layer; +#endif +}; + +#define GL_ERR(expr) \ + { \ + expr; \ + GLenum err = glGetError(); \ + if (err) { \ + NSLog(@"%s:%s: %x error", __FUNCTION__, #expr, err); \ + } \ + } + +class GLManagerApple : public GLManager { + DisplayServer::WindowID current_window = -1; + +public: + virtual Error initialize(void *p_native_display = nullptr) override; + virtual Error open_display(void *p_native_display = nullptr) override { return OK; } + virtual Error window_create(DisplayServer::WindowID p_id, Ref p_native_surface, int p_width, int p_height) override; + virtual void window_resize(DisplayServer::WindowID p_id, int p_width, int p_height) override; + virtual void window_make_current(DisplayServer::WindowID p_id) override; + virtual void release_current() override {} + virtual void swap_buffers() override; + virtual void window_destroy(DisplayServer::WindowID p_id) override; + virtual Size2i window_get_size(DisplayServer::WindowID p_id) override; + void deinitialize(); + + virtual void set_use_vsync(bool p_use) override {} + virtual bool is_using_vsync() const override { return false; } + + virtual int window_get_render_target(DisplayServer::WindowID p_window_id) const override; + virtual int window_get_color_texture(DisplayServer::WindowID p_id) const override { return 0; } + + virtual ~GLManagerApple() { + deinitialize(); + } + +protected: + Error create_framebuffer(DisplayServer::WindowID p_id, void *p_layer); + +private: + HashMap windows; +#if defined(IOS_ENABLED) + EAGLContext *context = nullptr; +#endif +}; + +Error GLManagerApple::initialize(void *p_native_display) { +#if defined(IOS_ENABLED) + // Create GL ES 3 context + if (OS::get_singleton()->get_current_rendering_method() == "gl_compatibility" && context == nullptr) { + context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3]; + ERR_FAIL_COND_V_MSG(!context, FAILED, "Failed to create OpenGL ES 3.0 context!"); + } + + if (![EAGLContext setCurrentContext:context]) { + ERR_FAIL_V_MSG(FAILED, "Unable to set current EAGLContext"); + } +#endif + return OK; +} + +Size2i GLManagerApple::window_get_size(DisplayServer::WindowID p_id) { + ERR_FAIL_COND_V(!windows.has(p_id), Size2i()); + WindowData &gles_data = windows[p_id]; + return Size2i(gles_data.layer.bounds.size.width, gles_data.layer.bounds.size.height); +} + +void GLManagerApple::window_resize(DisplayServer::WindowID p_id, int p_width, int p_height) { + ERR_FAIL_COND(!windows.has(p_id)); + WindowData &gles_data = windows[p_id]; +#if defined(IOS_ENABLED) + GL_ERR([EAGLContext setCurrentContext:context]); + CAEAGLLayer *layer = gles_data.layer; + window_destroy(p_id); + create_framebuffer(p_id, (__bridge void *)layer); +#endif +} + +void GLManagerApple::window_make_current(DisplayServer::WindowID p_id) { + ERR_FAIL_COND(!windows.has(p_id)); + WindowData &gles_data = windows[p_id]; +#if defined(IOS_ENABLED) + GL_ERR([EAGLContext setCurrentContext:context]); + GL_ERR(glBindFramebufferOES(GL_FRAMEBUFFER_OES, gles_data.viewFramebuffer)); + current_window = p_id; +#endif +} + +void GLManagerApple::swap_buffers() { + ERR_FAIL_COND(!windows.has(current_window)); + WindowData &gles_data = windows[current_window]; +#if defined(IOS_ENABLED) + GL_ERR([EAGLContext setCurrentContext:context]); + GL_ERR(glBindRenderbufferOES(GL_RENDERBUFFER_OES, gles_data.viewRenderbuffer)); + GL_ERR([context presentRenderbuffer:GL_RENDERBUFFER_OES]); +#endif +} + +void GLManagerApple::deinitialize() { +#if defined(IOS_ENABLED) + if ([EAGLContext currentContext] == context) { + [EAGLContext setCurrentContext:nil]; + } + + if (context) { + context = nil; + } +#endif +} + +Error GLManagerApple::window_create(DisplayServer::WindowID p_id, Ref p_native_surface, int p_width, int p_height) { +#if defined(IOS_ENABLED) + NSLog(@"GLESContextApple::create_framebuffer surface"); + CAEAGLLayer *layer = nullptr; + Ref apple_surface = Object::cast_to(*p_native_surface); + if (apple_surface.is_valid()) { + layer = (__bridge CAEAGLLayer *)(void *)apple_surface->get_layer(); + } + ERR_FAIL_COND_V_MSG(layer == nullptr, ERR_CANT_CREATE, "Unable to create GL window"); + + return create_framebuffer(p_id, (__bridge void *)layer); +#else + return FAILED; +#endif +} + +Error GLManagerApple::create_framebuffer(DisplayServer::WindowID p_id, void *p_layer) { + WindowData &gles_data = windows[p_id]; +#if defined(IOS_ENABLED) + NSLog(@"GLESContextApple::create_framebuffer layer"); + GL_ERR([EAGLContext setCurrentContext:context]); + gles_data.layer = (__bridge CAEAGLLayer *)p_layer; + + GL_ERR(glGenFramebuffersOES(1, &gles_data.viewFramebuffer)); + GL_ERR(glGenRenderbuffersOES(1, &gles_data.viewRenderbuffer)); + + GL_ERR(glBindFramebufferOES(GL_FRAMEBUFFER_OES, gles_data.viewFramebuffer)); + GL_ERR(glBindRenderbufferOES(GL_RENDERBUFFER_OES, gles_data.viewRenderbuffer)); + // This call associates the storage for the current render buffer with the EAGLDrawable (our CAself) + // allowing us to draw into a buffer that will later be rendered to screen wherever the layer is (which corresponds with our view). + [CATransaction flush]; + GL_ERR([context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:gles_data.layer]); + GL_ERR(glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, gles_data.viewRenderbuffer)); + + GL_ERR(glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &gles_data.backingWidth)); + GL_ERR(glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &gles_data.backingHeight)); + + // For this sample, we also need a depth buffer, so we'll create and attach one via another renderbuffer. + GL_ERR(glGenRenderbuffersOES(1, &gles_data.depthRenderbuffer)); + GL_ERR(glBindRenderbufferOES(GL_RENDERBUFFER_OES, gles_data.depthRenderbuffer)); + GL_ERR(glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, gles_data.backingWidth, gles_data.backingHeight)); + GL_ERR(glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, gles_data.depthRenderbuffer)); + + if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) { + NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES)); + return FAILED; + } + + return OK; +#else + return FAILED; +#endif +} + +// Clean up any buffers we have allocated. +void GLManagerApple::window_destroy(DisplayServer::WindowID p_id) { + ERR_FAIL_COND(!windows.has(p_id)); + WindowData &gles_data = windows[p_id]; +#if defined(IOS_ENABLED) + GL_ERR([EAGLContext setCurrentContext:context]); + GL_ERR(glDeleteFramebuffersOES(1, &gles_data.viewFramebuffer)); + gles_data.viewFramebuffer = 0; + GL_ERR(glDeleteRenderbuffersOES(1, &gles_data.viewRenderbuffer)); + gles_data.viewRenderbuffer = 0; + + if (gles_data.depthRenderbuffer) { + GL_ERR(glDeleteRenderbuffersOES(1, &gles_data.depthRenderbuffer)); + gles_data.depthRenderbuffer = 0; + } +#endif + windows.erase(p_id); +} + +int GLManagerApple::window_get_render_target(DisplayServer::WindowID p_id) const { + ERR_FAIL_COND_V(!windows.has(p_id), 0); + const WindowData &gles_data = windows[p_id]; + return gles_data.viewFramebuffer; +} + +#endif // GLES3_ENABLED + +void RenderingNativeSurfaceApple::_bind_methods() { + ClassDB::bind_static_method("RenderingNativeSurfaceApple", D_METHOD("create", "layer"), &RenderingNativeSurfaceApple::create_api); + ClassDB::bind_method(D_METHOD("get_layer"), &RenderingNativeSurfaceApple::get_layer); +} + +Ref RenderingNativeSurfaceApple::create_api(/* GDExtensionConstPtr */ uint64_t p_layer) { + return RenderingNativeSurfaceApple::create((void *)p_layer /* .operator const void *() */); +} + +Ref RenderingNativeSurfaceApple::create(void *p_layer) { + Ref result; + if (!p_layer) { + String rendering_driver = ::OS::get_singleton()->get_current_rendering_driver_name(); + CALayer *__block myLayer = nil; + dispatch_sync(dispatch_get_main_queue(), ^{ +#if defined(GLES3_ENABLED) + if (rendering_driver == "opengl3") { +#if defined(IOS_ENABLED) + myLayer = [[CAEAGLLayer alloc] init]; +#elif defined(MACOS_ENABLED) + myLayer = [[CAOpenGLLayer alloc] init]; +#endif + } +#endif + if (rendering_driver == "vulkan") { + myLayer = [[CAMetalLayer alloc] init]; + } + }); + if (!myLayer) { + return result; + } + p_layer = (void *)CFBridgingRetain(myLayer); + } else { + p_layer = (void *)CFBridgingRetain((__bridge CALayer *)p_layer); + } + + result.instantiate(); + result->layer = p_layer; + return result; +} + +uint64_t RenderingNativeSurfaceApple::get_layer() { + return (uint64_t)layer; +} + +void *RenderingNativeSurfaceApple::get_native_id() const { + return (void *)layer; +} + +RenderingContextDriver *RenderingNativeSurfaceApple::create_rendering_context(const String &p_rendering_driver) { +#if defined(VULKAN_ENABLED) + if (p_rendering_driver == "vulkan") { + return memnew(RenderingContextDriverVulkanApple); + } +#endif +#if defined(METAL_ENABLED) + if (p_rendering_driver == "metal") { + if (@available(ios 14.0, *)) { + return memnew(RenderingContextDriverMetal); + } + } +#endif + return nullptr; +} + +GLManager *RenderingNativeSurfaceApple::create_gl_manager(const String &p_driver_name) { +#if defined(GLES3_ENABLED) + if (p_driver_name == "opengl3") { + return memnew(GLManagerApple); + } +#endif + return nullptr; +} + +RenderingNativeSurfaceApple::RenderingNativeSurfaceApple() { +} + +RenderingNativeSurfaceApple::~RenderingNativeSurfaceApple() { + if (layer) { + CFBridgingRelease(layer); + } +} diff --git a/drivers/apple_embedded/SCsub b/drivers/apple_embedded/SCsub index 7a4b82bd9e08..ebecae48e459 100644 --- a/drivers/apple_embedded/SCsub +++ b/drivers/apple_embedded/SCsub @@ -3,6 +3,26 @@ from misc.utility.scons_hints import * Import("env") +common_files = [ + "apple_embedded.mm", + "display_server_apple_embedded.mm", + "godot_view_apple_embedded.mm", + "godot_view_renderer.mm", + "key_mapping_apple_embedded.mm", + "keyboard_input_view.mm", + "main_utilities.mm", + "os_apple_embedded.mm", + "tts_apple_embedded.mm", +] + +executable_files = [ + "app_delegate_service.mm", + "godot_app_delegate.mm", + "view_controller.mm", +] + +libgodot_files = [] + env_apple_embedded = env.Clone() # Enable module support @@ -13,4 +33,7 @@ vulkan_dir = "#thirdparty/vulkan" env_apple_embedded.Prepend(CPPPATH=[vulkan_dir, vulkan_dir + "/include"]) # Driver source files -env_apple_embedded.add_source_files(env.drivers_sources, "*.mm") +if env["library_type"] != "executable": + env_apple_embedded.add_source_files(env.drivers_sources, common_files + libgodot_files) +else: + env_apple_embedded.add_source_files(env.drivers_sources, common_files + executable_files) diff --git a/drivers/apple_embedded/apple_embedded.mm b/drivers/apple_embedded/apple_embedded.mm index 33d23061f071..8cc5243ff9ce 100644 --- a/drivers/apple_embedded/apple_embedded.mm +++ b/drivers/apple_embedded/apple_embedded.mm @@ -30,8 +30,10 @@ #import "apple_embedded.h" +#ifndef LIBGODOT_ENABLED #import "app_delegate_service.h" #import "view_controller.h" +#endif #import #import @@ -159,6 +161,7 @@ } void AppleEmbedded::alert(const char *p_alert, const char *p_title) { +#ifndef LIBGODOT_ENABLED NSString *title = [NSString stringWithUTF8String:p_title]; NSString *message = [NSString stringWithUTF8String:p_alert]; @@ -171,6 +174,7 @@ [alert addAction:button]; [GDTAppDelegateService.viewController presentViewController:alert animated:YES completion:nil]; +#endif } String AppleEmbedded::get_model() const { diff --git a/drivers/apple_embedded/display_layer_apple_embedded.h b/drivers/apple_embedded/display_layer_apple_embedded.h index 552b115a0843..be7cbba6b884 100644 --- a/drivers/apple_embedded/display_layer_apple_embedded.h +++ b/drivers/apple_embedded/display_layer_apple_embedded.h @@ -30,6 +30,7 @@ #pragma once +#include "servers/rendering/gl_manager.h" #import @protocol GDTDisplayLayer @@ -38,5 +39,6 @@ - (void)stopRenderDisplayLayer; - (void)initializeDisplayLayer; - (void)layoutDisplayLayer; +- (void)setupContext:(GLManager *)context withSurface:(Ref *)surface; @end diff --git a/drivers/apple_embedded/display_server_apple_embedded.h b/drivers/apple_embedded/display_server_apple_embedded.h index df7bcd9b345f..cb448164d818 100644 --- a/drivers/apple_embedded/display_server_apple_embedded.h +++ b/drivers/apple_embedded/display_server_apple_embedded.h @@ -38,7 +38,7 @@ #include "servers/rendering/rendering_device.h" #if defined(VULKAN_ENABLED) -#import "rendering_context_driver_vulkan_apple_embedded.h" +#import "drivers/apple/rendering_context_driver_vulkan_apple.h" #include "drivers/vulkan/godot_vulkan.h" #endif // VULKAN_ENABLED @@ -63,6 +63,9 @@ class DisplayServerAppleEmbedded : public DisplayServer { #if defined(RD_ENABLED) RenderingContextDriver *rendering_context = nullptr; RenderingDevice *rendering_device = nullptr; +#endif +#if defined(GLES3_ENABLED) + GLManager *gl_manager = nullptr; #endif NativeMenu *native_menu = nullptr; diff --git a/drivers/apple_embedded/display_server_apple_embedded.mm b/drivers/apple_embedded/display_server_apple_embedded.mm index 886a17dcef04..edc8e5269985 100644 --- a/drivers/apple_embedded/display_server_apple_embedded.mm +++ b/drivers/apple_embedded/display_server_apple_embedded.mm @@ -32,6 +32,7 @@ #import "app_delegate_service.h" #import "apple_embedded.h" +#import "display_layer_apple_embedded.h" #import "godot_view_apple_embedded.h" #import "key_mapping_apple_embedded.h" #import "keyboard_input_view.h" @@ -41,6 +42,7 @@ #include "core/config/project_settings.h" #include "core/io/file_access_pack.h" +#include "drivers/apple/rendering_native_surface_apple.h" #import @@ -64,40 +66,34 @@ bool has_made_render_compositor_current = false; + Ref apple_surface; + #if defined(RD_ENABLED) rendering_context = nullptr; rendering_device = nullptr; CALayer *layer = nullptr; - union { -#ifdef VULKAN_ENABLED - RenderingContextDriverVulkanAppleEmbedded::WindowPlatformData vulkan; -#endif -#ifdef METAL_ENABLED - GODOT_CLANG_WARNING_PUSH_AND_IGNORE("-Wunguarded-availability") - // Eliminate "RenderingContextDriverMetal is only available on iOS 14.0 or newer". - RenderingContextDriverMetal::WindowPlatformData metal; - GODOT_CLANG_WARNING_POP -#endif - } wpd; - #if defined(VULKAN_ENABLED) if (rendering_driver == "vulkan") { +#ifndef LIBGODOT_ENABLED layer = [GDTAppDelegateService.viewController.godotView initializeRenderingForDriver:@"vulkan"]; +#endif if (!layer) { ERR_FAIL_MSG("Failed to create iOS Vulkan rendering layer."); } - wpd.vulkan.layer_ptr = (CAMetalLayer *const *)&layer; - rendering_context = memnew(RenderingContextDriverVulkanAppleEmbedded); + apple_surface = RenderingNativeSurfaceApple::create((__bridge void *)layer); + rendering_context = apple_surface->create_rendering_context(rendering_driver); } #endif #ifdef METAL_ENABLED if (rendering_driver == "metal") { if (@available(iOS 14.0, *)) { +#ifndef LIBGODOT_ENABLED layer = [GDTAppDelegateService.viewController.godotView initializeRenderingForDriver:@"metal"]; - wpd.metal.layer = (CAMetalLayer *)layer; - rendering_context = memnew(RenderingContextDriverMetal); +#endif + apple_surface = RenderingNativeSurfaceApple::create((__bridge void *)layer); + rendering_context = apple_surface->create_rendering_context(rendering_driver); } else { OS::get_singleton()->alert("Metal is only supported on iOS 14.0 and later."); r_error = ERR_UNAVAILABLE; @@ -127,7 +123,7 @@ } if (rendering_context) { - if (rendering_context->window_create(MAIN_WINDOW_ID, &wpd) != OK) { + if (rendering_context->window_create(MAIN_WINDOW_ID, apple_surface) != OK) { ERR_PRINT(vformat("Failed to create %s window.", rendering_driver)); memdelete(rendering_context); rendering_context = nullptr; @@ -156,12 +152,20 @@ #if defined(GLES3_ENABLED) if (rendering_driver == "opengl3") { - CALayer *layer = [GDTAppDelegateService.viewController.godotView initializeRenderingForDriver:@"opengl3"]; + CALayer *layer = nullptr; +#ifndef LIBGODOT_ENABLED + layer = [GDTAppDelegateService.viewController.godotView initializeRenderingForDriver:@"opengl3"]; +#endif if (!layer) { ERR_FAIL_MSG("Failed to create iOS OpenGLES rendering layer."); } + apple_surface = RenderingNativeSurfaceApple::create((__bridge void *)layer); + gl_manager = apple_surface->create_gl_manager(rendering_driver); + Ref native_surface = Ref(Object::cast_to(apple_surface.ptr())); + [layer setupContext:gl_manager withSurface:&native_surface]; + RasterizerGLES3::make_current(false); has_made_render_compositor_current = true; } @@ -478,7 +482,10 @@ Rect2i DisplayServerAppleEmbedded::get_display_safe_area() const { UIEdgeInsets insets = UIEdgeInsetsZero; - UIView *view = GDTAppDelegateService.viewController.godotView; + UIView *view = nullptr; +#ifndef LIBGODOT_ENABLED + view = GDTAppDelegateService.viewController.godotView; +#endif if ([view respondsToSelector:@selector(safeAreaInsets)]) { insets = [view safeAreaInsets]; } @@ -509,7 +516,10 @@ int screen_count = get_screen_count(); ERR_FAIL_INDEX_V(p_screen, screen_count, Size2i()); - CALayer *layer = GDTAppDelegateService.viewController.godotView.renderingLayer; + CALayer *layer = nullptr; +#ifndef LIBGODOT_ENABLED + layer = GDTAppDelegateService.viewController.godotView.renderingLayer; +#endif if (!layer) { return Size2i(); @@ -542,12 +552,22 @@ case DISPLAY_HANDLE: { return 0; // Not supported. } +#ifndef LIBGODOT_ENABLED case WINDOW_HANDLE: { return (int64_t)GDTAppDelegateService.viewController; } case WINDOW_VIEW: { return (int64_t)GDTAppDelegateService.viewController.godotView; } +#endif +#if defined(GLES3_ENABLED) + case OPENGL_FBO: { + if (rendering_driver == "opengl3") { + return (int64_t)gl_manager->window_get_render_target(DisplayServer::MAIN_WINDOW_ID); + } + return 0; + } +#endif default: { return 0; } @@ -664,7 +684,9 @@ screen_orientation = p_orientation; if (@available(iOS 16.0, *)) { +#ifndef LIBGODOT_ENABLED [GDTAppDelegateService.viewController setNeedsUpdateOfSupportedInterfaceOrientations]; +#endif } #if !defined(VISIONOS_ENABLED) else { @@ -706,6 +728,7 @@ _FORCE_INLINE_ int _convert_utf32_offset_to_utf16(const String &p_existing_text, void DisplayServerAppleEmbedded::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, VirtualKeyboardType p_type, int p_max_length, int p_cursor_start, int p_cursor_end) { NSString *existingString = [[NSString alloc] initWithUTF8String:p_existing_text.utf8().get_data()]; +#ifndef LIBGODOT_ENABLED GDTAppDelegateService.viewController.keyboardView.keyboardType = UIKeyboardTypeDefault; GDTAppDelegateService.viewController.keyboardView.textContentType = nil; switch (p_type) { @@ -743,14 +766,21 @@ _FORCE_INLINE_ int _convert_utf32_offset_to_utf16(const String &p_existing_text, becomeFirstResponderWithString:existingString cursorStart:_convert_utf32_offset_to_utf16(p_existing_text, p_cursor_start) cursorEnd:_convert_utf32_offset_to_utf16(p_existing_text, p_cursor_end)]; +#endif } bool DisplayServerAppleEmbedded::is_keyboard_active() const { +#ifndef LIBGODOT_ENABLED return [GDTAppDelegateService.viewController.keyboardView isFirstResponder]; +#else + return false; +#endif } void DisplayServerAppleEmbedded::virtual_keyboard_hide() { +#ifndef LIBGODOT_ENABLED [GDTAppDelegateService.viewController.keyboardView resignFirstResponder]; +#endif } void DisplayServerAppleEmbedded::virtual_keyboard_set_height(int height) { diff --git a/drivers/apple_embedded/os_apple_embedded.h b/drivers/apple_embedded/os_apple_embedded.h index e799c0a71a7a..a61a361f1ecc 100644 --- a/drivers/apple_embedded/os_apple_embedded.h +++ b/drivers/apple_embedded/os_apple_embedded.h @@ -44,7 +44,7 @@ #include "servers/rendering/rendering_device.h" #if defined(VULKAN_ENABLED) -#import "rendering_context_driver_vulkan_apple_embedded.h" +#import "drivers/apple/rendering_context_driver_vulkan_apple.h" #endif #endif @@ -53,7 +53,9 @@ class OS_AppleEmbedded : public OS_Unix { static HashMap dynamic_symbol_lookup_table; friend void register_dynamic_symbol(char *name, void *address); +#ifdef COREAUDIO_ENABLED AudioDriverCoreAudio audio_driver; +#endif AppleEmbedded *apple_embedded = nullptr; diff --git a/drivers/apple_embedded/os_apple_embedded.mm b/drivers/apple_embedded/os_apple_embedded.mm index 07d1f8a270c7..2e9271d8c587 100644 --- a/drivers/apple_embedded/os_apple_embedded.mm +++ b/drivers/apple_embedded/os_apple_embedded.mm @@ -32,16 +32,19 @@ #ifdef APPLE_EMBEDDED_ENABLED +#ifndef LIBGODOT_ENABLED #import "app_delegate_service.h" #import "display_server_apple_embedded.h" #import "godot_view_apple_embedded.h" #import "view_controller.h" +#endif #include "core/config/project_settings.h" #include "core/io/dir_access.h" #include "core/io/file_access.h" #import "drivers/apple/os_log_logger.h" #include "main/main.h" +#include "servers/display_server_embedded.h" #import #import @@ -144,7 +147,9 @@ Rect2 fit_keep_aspect_covered(const Vector2 &p_container, const Vector2 &p_rect) loggers.push_back(memnew(OsLogLogger(NSBundle.mainBundle.bundleIdentifier.UTF8String))); _set_logger(memnew(CompositeLogger(loggers))); +#ifdef COREAUDIO_ENABLED AudioDriverManager::add_driver(&audio_driver); +#endif } OS_AppleEmbedded::~OS_AppleEmbedded() {} @@ -665,17 +670,23 @@ Rect2 fit_keep_aspect_covered(const Vector2 &p_container, const Vector2 &p_rect) if (is_focused) { is_focused = false; +#ifndef LIBGODOT_ENABLED if (DisplayServerAppleEmbedded::get_singleton()) { DisplayServerAppleEmbedded::get_singleton()->send_window_event(DisplayServer::WINDOW_EVENT_FOCUS_OUT); } +#endif if (OS::get_singleton()->get_main_loop()) { OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT); } +#ifndef LIBGODOT_ENABLED [GDTAppDelegateService.viewController.godotView stopRendering]; +#endif +#ifdef COREAUDIO_ENABLED audio_driver.stop(); +#endif } } @@ -683,26 +694,34 @@ Rect2 fit_keep_aspect_covered(const Vector2 &p_container, const Vector2 &p_rect) if (!is_focused) { is_focused = true; +#ifndef LIBGODOT_ENABLED if (DisplayServerAppleEmbedded::get_singleton()) { DisplayServerAppleEmbedded::get_singleton()->send_window_event(DisplayServer::WINDOW_EVENT_FOCUS_IN); } +#endif if (OS::get_singleton()->get_main_loop()) { OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_IN); } +#ifndef LIBGODOT_ENABLED [GDTAppDelegateService.viewController.godotView startRendering]; +#endif +#ifdef COREAUDIO_ENABLED audio_driver.start(); +#endif } } void OS_AppleEmbedded::on_enter_background() { // Do not check for is_focused, because on_focus_out will always be fired first by applicationWillResignActive. +#ifndef LIBGODOT_ENABLED if (OS::get_singleton()->get_main_loop()) { OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_PAUSED); } +#endif on_focus_out(); } @@ -711,9 +730,11 @@ Rect2 fit_keep_aspect_covered(const Vector2 &p_container, const Vector2 &p_rect) if (!is_focused) { on_focus_in(); +#ifndef LIBGODOT_ENABLED if (OS::get_singleton()->get_main_loop()) { OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_RESUMED); } +#endif } } diff --git a/drivers/coreaudio/audio_driver_coreaudio.mm b/drivers/coreaudio/audio_driver_coreaudio.mm index 6f9f690d5280..79f075092438 100644 --- a/drivers/coreaudio/audio_driver_coreaudio.mm +++ b/drivers/coreaudio/audio_driver_coreaudio.mm @@ -151,7 +151,7 @@ strdesc.mBytesPerPacket = strdesc.mBytesPerFrame * strdesc.mFramesPerPacket; result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &strdesc, sizeof(strdesc)); - ERR_FAIL_COND_V(result != noErr, FAILED); + ERR_FAIL_COND_V_MSG(result != noErr, FAILED, String::utf8("Result: {}").format(result)); uint32_t latency = Engine::get_singleton()->get_audio_output_latency(); // Sample rate is independent of channels (ref: https://stackoverflow.com/questions/11048825/audio-sample-frequency-rely-on-channels) @@ -159,7 +159,7 @@ #ifdef MACOS_ENABLED result = AudioUnitSetProperty(audio_unit, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, kOutputBus, &buffer_frames, sizeof(UInt32)); - ERR_FAIL_COND_V(result != noErr, FAILED); + ERR_FAIL_COND_V_MSG(result != noErr, FAILED, String::utf8("Result: {}").format(result)); #endif unsigned int buffer_size = buffer_frames * channels; @@ -174,10 +174,10 @@ callback.inputProc = &AudioDriverCoreAudio::output_callback; callback.inputProcRefCon = this; result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback)); - ERR_FAIL_COND_V(result != noErr, FAILED); + ERR_FAIL_COND_V_MSG(result != noErr, FAILED, String::utf8("Result: {}").format(result)); result = AudioUnitInitialize(audio_unit); - ERR_FAIL_COND_V(result != noErr, FAILED); + ERR_FAIL_COND_V_MSG(result != noErr, FAILED, String::utf8("Result: {}").format(result)); if (GLOBAL_GET("audio/driver/enable_input")) { return init_input_device(); @@ -379,7 +379,7 @@ ERR_FAIL_NULL_V(comp, FAILED); OSStatus result = AudioComponentInstanceNew(comp, &input_unit); - ERR_FAIL_COND_V(result != noErr, FAILED); + ERR_FAIL_COND_V_MSG(result != noErr, FAILED, String::utf8("Result: {}").format(result)); #ifdef MACOS_ENABLED AudioObjectPropertyAddress prop; @@ -388,12 +388,12 @@ prop.mElement = kAudioObjectPropertyElementMain; result = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &prop, &input_device_address_cb, this); - ERR_FAIL_COND_V(result != noErr, FAILED); + ERR_FAIL_COND_V_MSG(result != noErr, FAILED, String::utf8("Result: {}").format(result)); #endif UInt32 flag = 1; result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &flag, sizeof(flag)); - ERR_FAIL_COND_V(result != noErr, FAILED); + ERR_FAIL_COND_V_MSG(result != noErr, FAILED, String::utf8("Result: {}").format(result)); UInt32 size; #ifdef MACOS_ENABLED @@ -402,17 +402,17 @@ AudioObjectPropertyAddress property = { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMain }; result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &property, 0, nullptr, &size, &device_id); - ERR_FAIL_COND_V(result != noErr, FAILED); + ERR_FAIL_COND_V_MSG(result != noErr, FAILED, String::utf8("Result: {}").format(result)); result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &device_id, sizeof(AudioDeviceID)); - ERR_FAIL_COND_V(result != noErr, FAILED); + ERR_FAIL_COND_V_MSG(result != noErr, FAILED, String::utf8("Result: {}").format(result)); #endif AudioStreamBasicDescription strdesc; memset(&strdesc, 0, sizeof(strdesc)); size = sizeof(strdesc); result = AudioUnitGetProperty(input_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &strdesc, &size); - ERR_FAIL_COND_V(result != noErr, FAILED); + ERR_FAIL_COND_V_MSG(result != noErr, FAILED, String::utf8("Result: {}").format(result)); switch (strdesc.mChannelsPerFrame) { case 1: // Mono @@ -452,7 +452,7 @@ strdesc.mBytesPerPacket = strdesc.mBytesPerFrame * strdesc.mFramesPerPacket; result = AudioUnitSetProperty(input_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &strdesc, sizeof(strdesc)); - ERR_FAIL_COND_V(result != noErr, FAILED); + ERR_FAIL_COND_V_MSG(result != noErr, FAILED, String::utf8("Result: {}").format(result)); uint32_t latency = Engine::get_singleton()->get_audio_output_latency(); // Sample rate is independent of channels (ref: https://stackoverflow.com/questions/11048825/audio-sample-frequency-rely-on-channels) @@ -465,10 +465,10 @@ callback.inputProc = &AudioDriverCoreAudio::input_callback; callback.inputProcRefCon = this; result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, kInputBus, &callback, sizeof(callback)); - ERR_FAIL_COND_V(result != noErr, FAILED); + ERR_FAIL_COND_V_MSG(result != noErr, FAILED, String::utf8("Result: {}").format(result)); result = AudioUnitInitialize(input_unit); - ERR_FAIL_COND_V(result != noErr, FAILED); + ERR_FAIL_COND_V_MSG(result != noErr, FAILED, String::utf8("Result: {}").format(result)); print_verbose("CoreAudio: input sampling rate: " + itos(capture_mix_rate) + " Hz"); print_verbose("CoreAudio: input audio buffer frames: " + itos(capture_buffer_frames) + " calculated latency: " + itos(capture_buffer_frames * 1000 / capture_mix_rate) + "ms"); @@ -665,14 +665,14 @@ AudioObjectPropertyAddress property = { elem, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMain }; OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &property, 0, nullptr, &size, &device_id); - ERR_FAIL_COND(result != noErr); + ERR_FAIL_COND_MSG(result != noErr, String::utf8("Result: {}").format(result)); found = true; } if (found) { OSStatus result = AudioUnitSetProperty(input ? input_unit : audio_unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &device_id, sizeof(AudioDeviceID)); - ERR_FAIL_COND(result != noErr); + ERR_FAIL_COND_MSG(result != noErr, String::utf8("Result: {}").format(result)); if (input) { // Reset audio input to keep synchronization. diff --git a/drivers/d3d12/rendering_context_driver_d3d12.cpp b/drivers/d3d12/rendering_context_driver_d3d12.cpp index 59710b565fcd..670c61340af4 100644 --- a/drivers/d3d12/rendering_context_driver_d3d12.cpp +++ b/drivers/d3d12/rendering_context_driver_d3d12.cpp @@ -258,10 +258,11 @@ void RenderingContextDriverD3D12::driver_free(RenderingDeviceDriver *p_driver) { memdelete(p_driver); } -RenderingContextDriver::SurfaceID RenderingContextDriverD3D12::surface_create(const void *p_platform_data) { - const WindowPlatformData *wpd = (const WindowPlatformData *)(p_platform_data); +RenderingContextDriver::SurfaceID RenderingContextDriverD3D12::surface_create(Ref p_native_surface) { + Ref windows_native_surface = Object::cast_to(*p_native_surface); + ERR_FAIL_COND_V(windows_native_surface.is_null(), SurfaceID()); Surface *surface = memnew(Surface); - surface->hwnd = wpd->window; + surface->hwnd = windows_native_surface->get_window_handle(); return SurfaceID(surface); } diff --git a/drivers/d3d12/rendering_context_driver_d3d12.h b/drivers/d3d12/rendering_context_driver_d3d12.h index 20d4c7b135b2..fb4982b83d35 100644 --- a/drivers/d3d12/rendering_context_driver_d3d12.h +++ b/drivers/d3d12/rendering_context_driver_d3d12.h @@ -71,7 +71,7 @@ class RenderingContextDriverD3D12 : public RenderingContextDriver { virtual bool device_supports_present(uint32_t p_device_index, SurfaceID p_surface) const override; virtual RenderingDeviceDriver *driver_create() override; virtual void driver_free(RenderingDeviceDriver *p_driver) override; - virtual SurfaceID surface_create(const void *p_platform_data) override; + virtual SurfaceID surface_create(Ref p_native_surface) override; virtual void surface_set_size(SurfaceID p_surface, uint32_t p_width, uint32_t p_height) override; virtual void surface_set_vsync_mode(SurfaceID p_surface, DisplayServer::VSyncMode p_vsync_mode) override; virtual DisplayServer::VSyncMode surface_get_vsync_mode(SurfaceID p_surface) const override; @@ -82,11 +82,6 @@ class RenderingContextDriverD3D12 : public RenderingContextDriver { virtual void surface_destroy(SurfaceID p_surface) override; virtual bool is_debug_utils_enabled() const override; - // Platform-specific data for the Windows embedded in this driver. - struct WindowPlatformData { - HWND window; - }; - // D3D12-only methods. struct Surface { HWND hwnd = nullptr; diff --git a/drivers/egl/egl_manager.cpp b/drivers/egl/egl_manager.cpp index 5f7aca41cf7f..ee7143871e17 100644 --- a/drivers/egl/egl_manager.cpp +++ b/drivers/egl/egl_manager.cpp @@ -248,6 +248,11 @@ int EGLManager::display_get_native_visual_id(void *p_display) { return native_visual_id; } +Error EGLManager::window_create(DisplayServer::WindowID p_window_id, Ref p_native_surface, int p_width, int p_height) { + ERR_FAIL_COND_V_MSG(!p_native_surface.is_valid(), FAILED, "Invalid native surface"); + return window_create(p_window_id, nullptr, p_native_surface->get_native_id(), p_width, p_height); +} + Error EGLManager::window_create(DisplayServer::WindowID p_window_id, void *p_display, void *p_native_window, int p_width, int p_height) { int gldisplay_id = _get_gldisplay_id(p_display); ERR_FAIL_COND_V(gldisplay_id < 0, ERR_CANT_CREATE); @@ -336,6 +341,10 @@ void EGLManager::window_destroy(DisplayServer::WindowID p_window_id) { } } +Size2i EGLManager::window_get_size(DisplayServer::WindowID p_id) { + return Size2i(); +} + void EGLManager::release_current() { if (!current_window) { return; diff --git a/drivers/egl/egl_manager.h b/drivers/egl/egl_manager.h index bd18e182189e..4390ed30f268 100644 --- a/drivers/egl/egl_manager.h +++ b/drivers/egl/egl_manager.h @@ -37,8 +37,9 @@ #include "core/templates/local_vector.h" #include "servers/display_server.h" +#include "servers/rendering/gl_manager.h" -class EGLManager { +class EGLManager : public GLManager { private: // An EGL-side representation of a display with its own rendering // context. @@ -94,24 +95,27 @@ class EGLManager { public: int display_get_native_visual_id(void *p_display); - Error open_display(void *p_display); + Error open_display(void *p_display) override; Error window_create(DisplayServer::WindowID p_window_id, void *p_display, void *p_native_window, int p_width, int p_height); + Error window_create(DisplayServer::WindowID p_window_id, Ref p_native_surface, int p_width, int p_height) override; + void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) override {} + void window_destroy(DisplayServer::WindowID p_window_id) override; + int window_get_render_target(DisplayServer::WindowID p_window_id) const override { return 0; } + int window_get_color_texture(DisplayServer::WindowID p_id) const override { return 0; } + Size2i window_get_size(DisplayServer::WindowID p_id) override; + void release_current() override; + void swap_buffers() override; - void window_destroy(DisplayServer::WindowID p_window_id); + void window_make_current(DisplayServer::WindowID p_window_id) override; - void release_current(); - void swap_buffers(); - - void window_make_current(DisplayServer::WindowID p_window_id); - - void set_use_vsync(bool p_use); - bool is_using_vsync() const; + void set_use_vsync(bool p_use) override; + bool is_using_vsync() const override; EGLContext get_context(DisplayServer::WindowID p_window_id); EGLDisplay get_display(DisplayServer::WindowID p_window_id); EGLConfig get_config(DisplayServer::WindowID p_window_id); - Error initialize(void *p_native_display = nullptr); + Error initialize(void *p_native_display = nullptr) override; EGLManager(); virtual ~EGLManager(); diff --git a/drivers/gles3/effects/copy_effects.cpp b/drivers/gles3/effects/copy_effects.cpp index e7b5a1721e73..12e921922ee6 100644 --- a/drivers/gles3/effects/copy_effects.cpp +++ b/drivers/gles3/effects/copy_effects.cpp @@ -32,6 +32,7 @@ #include "copy_effects.h" #include "../storage/texture_storage.h" +#include "../storage/utilities.h" using namespace GLES3; @@ -214,6 +215,8 @@ void CopyEffects::copy_cube_to_panorama(float p_mip_level) { // Intended for efficiently mipmapping textures. void CopyEffects::bilinear_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region) { GLuint framebuffers[2]; + FramebufferBinding read_binding(GL_READ_FRAMEBUFFER); + FramebufferBinding draw_binding(GL_DRAW_FRAMEBUFFER); glGenFramebuffers(2, framebuffers); glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffers[0]); glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_source_texture, 0); @@ -231,8 +234,8 @@ void CopyEffects::bilinear_blur(GLuint p_source_texture, int p_mipmap_count, con glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffers[i % 2]); source_region = dest_region; } - glBindFramebuffer(GL_READ_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); + read_binding.reset(); + draw_binding.reset(); glDeleteFramebuffers(2, framebuffers); } @@ -240,7 +243,7 @@ void CopyEffects::bilinear_blur(GLuint p_source_texture, int p_mipmap_count, con void CopyEffects::gaussian_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region, const Size2i &p_size) { GLuint framebuffer; glGenFramebuffers(1, &framebuffer); - glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); + FramebufferBinding binding(GL_FRAMEBUFFER, framebuffer); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, p_source_texture); @@ -297,7 +300,7 @@ void CopyEffects::gaussian_blur(GLuint p_source_texture, int p_mipmap_count, con source_region = dest_region; normalized_source_region = normalized_dest_region; } - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); + binding.reset(); glDeleteFramebuffers(1, &framebuffer); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); diff --git a/drivers/gles3/effects/cubemap_filter.cpp b/drivers/gles3/effects/cubemap_filter.cpp index cc4e370757cd..4b97a76eda59 100644 --- a/drivers/gles3/effects/cubemap_filter.cpp +++ b/drivers/gles3/effects/cubemap_filter.cpp @@ -33,6 +33,7 @@ #include "cubemap_filter.h" #include "../storage/texture_storage.h" +#include "../storage/utilities.h" #include "core/config/project_settings.h" using namespace GLES3; @@ -129,7 +130,7 @@ Vector2 hammersley(uint32_t i, uint32_t N) { void CubemapFilter::filter_radiance(GLuint p_source_cubemap, GLuint p_dest_cubemap, GLuint p_dest_framebuffer, int p_source_size, int p_mipmap_count, int p_layer) { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_CUBE_MAP, p_source_cubemap); - glBindFramebuffer(GL_FRAMEBUFFER, p_dest_framebuffer); + FramebufferBinding binding(GL_FRAMEBUFFER, p_dest_framebuffer); CubemapFilterShaderGLES3::ShaderVariant mode = CubemapFilterShaderGLES3::MODE_DEFAULT; @@ -207,7 +208,6 @@ void CubemapFilter::filter_radiance(GLuint p_source_cubemap, GLuint p_dest_cubem glDrawArrays(GL_TRIANGLES, 0, 3); } glBindVertexArray(0); - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); } #endif // GLES3_ENABLED diff --git a/drivers/gles3/effects/glow.cpp b/drivers/gles3/effects/glow.cpp index 9728b089aad9..f8f5c0c04949 100644 --- a/drivers/gles3/effects/glow.cpp +++ b/drivers/gles3/effects/glow.cpp @@ -32,6 +32,7 @@ #include "glow.h" #include "../storage/texture_storage.h" +#include "../storage/utilities.h" using namespace GLES3; @@ -97,6 +98,8 @@ void Glow::process_glow(GLuint p_source_color, Size2i p_size, const Glow::GLOWLE glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); + FramebufferBinding binding(GL_FRAMEBUFFER); + // Start with our filter pass { glBindFramebuffer(GL_FRAMEBUFFER, p_glow_buffers[0].fbo); @@ -167,7 +170,6 @@ void Glow::process_glow(GLuint p_source_color, Size2i p_size, const Glow::GLOWLE glDepthMask(GL_TRUE); glUseProgram(0); glBindTexture(GL_TEXTURE_2D, 0); - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); } #endif // GLES3_ENABLED diff --git a/drivers/gles3/effects/post_effects.cpp b/drivers/gles3/effects/post_effects.cpp index 105c8f6b71a2..df69971a85a2 100644 --- a/drivers/gles3/effects/post_effects.cpp +++ b/drivers/gles3/effects/post_effects.cpp @@ -32,6 +32,7 @@ #include "post_effects.h" #include "../storage/texture_storage.h" +#include "../storage/utilities.h" using namespace GLES3; @@ -92,7 +93,7 @@ void PostEffects::post_copy(GLuint p_dest_framebuffer, Size2i p_dest_size, GLuin glDepthMask(GL_FALSE); glDisable(GL_BLEND); - glBindFramebuffer(GL_FRAMEBUFFER, p_dest_framebuffer); + FramebufferBinding binding(GL_FRAMEBUFFER, p_dest_framebuffer); glViewport(0, 0, p_dest_size.x, p_dest_size.y); PostShaderGLES3::ShaderVariant mode = PostShaderGLES3::MODE_DEFAULT; @@ -147,7 +148,6 @@ void PostEffects::post_copy(GLuint p_dest_framebuffer, Size2i p_dest_size, GLuin glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); glUseProgram(0); - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); } #endif // GLES3_ENABLED diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index bafd693a7aac..a851fd3ac41e 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -44,6 +44,7 @@ #include "storage/mesh_storage.h" #include "storage/particles_storage.h" #include "storage/texture_storage.h" +#include "storage/utilities.h" void RasterizerCanvasGLES3::_update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4) { p_mat4[0] = p_transform.columns[0][0]; @@ -1651,7 +1652,7 @@ void RasterizerCanvasGLES3::light_update_shadow(RID p_rid, int p_shadow_index, c cl->shadow.z_far = p_far; cl->shadow.y_offset = float(p_shadow_index * 2 + 1) / float(data.max_lights_per_render * 2); - glBindFramebuffer(GL_FRAMEBUFFER, state.shadow_fb); + FramebufferBinding binding(GL_FRAMEBUFFER, state.shadow_fb); glViewport(0, p_shadow_index * 2, state.shadow_texture_size, 2); glDepthMask(GL_TRUE); @@ -1749,7 +1750,6 @@ void RasterizerCanvasGLES3::light_update_shadow(RID p_rid, int p_shadow_index, c } glBindVertexArray(0); - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); glDepthMask(GL_FALSE); glDisable(GL_DEPTH_TEST); glDisable(GL_SCISSOR_TEST); @@ -1784,7 +1784,7 @@ void RasterizerCanvasGLES3::light_update_directional_shadow(RID p_rid, int p_sha to_light_xform.invert(); - glBindFramebuffer(GL_FRAMEBUFFER, state.shadow_fb); + FramebufferBinding binding(GL_FRAMEBUFFER, state.shadow_fb); glViewport(0, p_shadow_index * 2, state.shadow_texture_size, 2); glDepthMask(GL_TRUE); @@ -1857,7 +1857,6 @@ void RasterizerCanvasGLES3::light_update_directional_shadow(RID p_rid, int p_sha cl->shadow.directional_xform = to_shadow * to_light_xform; glBindVertexArray(0); - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); glDepthMask(GL_FALSE); glDisable(GL_DEPTH_TEST); glDisable(GL_SCISSOR_TEST); @@ -1871,7 +1870,7 @@ void RasterizerCanvasGLES3::_update_shadow_atlas() { glActiveTexture(GL_TEXTURE0); glGenFramebuffers(1, &state.shadow_fb); - glBindFramebuffer(GL_FRAMEBUFFER, state.shadow_fb); + FramebufferBinding binding(GL_FRAMEBUFFER, state.shadow_fb); glGenRenderbuffers(1, &state.shadow_depth_buffer); glBindRenderbuffer(GL_RENDERBUFFER, state.shadow_depth_buffer); @@ -1905,7 +1904,6 @@ void RasterizerCanvasGLES3::_update_shadow_atlas() { WARN_PRINT("Could not create CanvasItem shadow atlas, status: " + GLES3::TextureStorage::get_singleton()->get_framebuffer_error(status)); } GLES3::Utilities::get_singleton()->texture_allocated_data(state.shadow_texture, state.shadow_texture_size * data.max_lights_per_render * 2 * 4, "2D shadow atlas texture"); - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); } } @@ -1927,7 +1925,7 @@ void RasterizerCanvasGLES3::render_sdf(RID p_render_target, LightOccluderInstanc to_clip = to_clip * to_sdf.affine_inverse(); - glBindFramebuffer(GL_FRAMEBUFFER, fb); + FramebufferBinding binding(GL_FRAMEBUFFER, fb); glViewport(0, 0, rect.size.width, rect.size.height); glDepthMask(GL_FALSE); @@ -1971,7 +1969,6 @@ void RasterizerCanvasGLES3::render_sdf(RID p_render_target, LightOccluderInstanc texture_storage->render_target_sdf_process(p_render_target); //done rendering, process it glBindVertexArray(0); - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); } RID RasterizerCanvasGLES3::occluder_polygon_create() { diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index 61eeb064e649..bb748ca67ef8 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -38,6 +38,7 @@ #include "core/io/image.h" #include "core/os/os.h" #include "storage/texture_storage.h" +#include "storage/utilities.h" #define _EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242 #define _EXT_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243 @@ -236,11 +237,44 @@ void *_egl_load_function_wrapper(const char *p_name) { } #endif +#ifdef GLAD_ENABLED +bool RasterizerGLES3::glad_loaded = false; +GLADloadfunc RasterizerGLES3::gl_get_proc_addr = nullptr; + +void RasterizerGLES3::preloadGL(GLADloadfunc p_load_func) { + if (glad_loaded) { + return; + } + if (gles_over_gl) { + if (p_load_func != nullptr) { + if (gladLoadGLES2(p_load_func)) { + gl_get_proc_addr = p_load_func; + glad_loaded = true; + } + } else { + if (gladLoaderLoadGLES2()) { + glad_loaded = true; + } + } + } else { + if (p_load_func != nullptr) { + if (gladLoadGL(p_load_func)) { + gl_get_proc_addr = p_load_func; + glad_loaded = true; + } + } else { + if (gladLoaderLoadGL()) { + glad_loaded = true; + } + } + } +} +#endif + RasterizerGLES3::RasterizerGLES3() { singleton = this; #ifdef GLAD_ENABLED - bool glad_loaded = false; #ifdef EGL_ENABLED // There should be a more flexible system for getting the GL pointer, as @@ -307,11 +341,14 @@ RasterizerGLES3::RasterizerGLES3() { } #endif // GL_API_ENABLED #ifdef GLES_API_ENABLED + if (gl_get_proc_addr == nullptr) { + gl_get_proc_addr = eglGetProcAddress; + } if (!gles_over_gl) { if (OS::get_singleton()->is_stdout_verbose()) { - DebugMessageCallbackARB callback = (DebugMessageCallbackARB)eglGetProcAddress("glDebugMessageCallback"); + DebugMessageCallbackARB callback = (DebugMessageCallbackARB)gl_get_proc_addr("glDebugMessageCallback"); if (!callback) { - callback = (DebugMessageCallbackARB)eglGetProcAddress("glDebugMessageCallbackKHR"); + callback = (DebugMessageCallbackARB)gl_get_proc_addr("glDebugMessageCallbackKHR"); } if (callback) { @@ -380,6 +417,9 @@ RasterizerGLES3::RasterizerGLES3() { } RasterizerGLES3::~RasterizerGLES3() { + if (singleton == this) { + singleton = nullptr; + } } void RasterizerGLES3::_blit_render_target_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen &p_blit, bool p_first) { @@ -388,7 +428,7 @@ void RasterizerGLES3::_blit_render_target_to_screen(DisplayServer::WindowID p_sc ERR_FAIL_NULL(rt); // We normally render to the render target upside down, so flip Y when blitting to the screen. - bool flip_y = true; + bool flip_y = DisplayServer::get_singleton()->is_rendering_flipped(); bool linear_to_srgb = false; if (rt->overridden.color.is_valid()) { // If we've overridden the render target's color texture, that means we @@ -410,7 +450,7 @@ void RasterizerGLES3::_blit_render_target_to_screen(DisplayServer::WindowID p_sc } #endif - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, DisplayServer::get_singleton()->window_get_native_handle(DisplayServer::OPENGL_FBO, p_screen)); if (p_first) { if (p_blit.dst_rect.position != Vector2() || p_blit.dst_rect.size != rt->size) { @@ -463,14 +503,19 @@ void RasterizerGLES3::blit_render_targets_to_screen(DisplayServer::WindowID p_sc } } -void RasterizerGLES3::set_boot_image(const Ref &p_image, const Color &p_color, bool p_scale, bool p_use_filter) { +void RasterizerGLES3::set_boot_image(const Ref &p_image, const Color &p_color, bool p_scale, DisplayServer::WindowID p_screen, bool p_use_filter) { if (p_image.is_null() || p_image->is_empty()) { return; } - Size2i win_size = DisplayServer::get_singleton()->window_get_size(); + Size2i win_size = DisplayServer::get_singleton()->window_get_size(p_screen); + + if (OS::get_singleton()->get_current_rendering_method() == "gl_compatibility") { + // This is currently needed for GLES to keep the current window being rendered to up to date + DisplayServer::get_singleton()->gl_window_make_current(p_screen); + } - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); + glBindFramebuffer(GL_FRAMEBUFFER, DisplayServer::get_singleton()->window_get_native_handle(DisplayServer::OPENGL_FBO, p_screen)); glViewport(0, 0, win_size.width, win_size.height); glEnable(GL_BLEND); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h index 375a15888e7d..ce744c81d79c 100644 --- a/drivers/gles3/rasterizer_gles3.h +++ b/drivers/gles3/rasterizer_gles3.h @@ -62,6 +62,10 @@ class RasterizerGLES3 : public RendererCompositor { #endif static bool gles_over_gl; + static bool glad_loaded; +#ifdef GLAD_ENABLED + static GLADloadfunc gl_get_proc_addr; +#endif protected: GLES3::Config *config = nullptr; @@ -96,7 +100,7 @@ class RasterizerGLES3 : public RendererCompositor { RendererCanvasRender *get_canvas() { return canvas; } RendererSceneRender *get_scene() { return scene; } - void set_boot_image(const Ref &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true); + void set_boot_image(const Ref &p_image, const Color &p_color, bool p_scale, DisplayServer::WindowID p_screen, bool p_use_filter = true); void initialize(); void begin_frame(double frame_step); @@ -113,6 +117,10 @@ class RasterizerGLES3 : public RendererCompositor { return memnew(RasterizerGLES3); } +#ifdef GLAD_ENABLED + static void preloadGL(GLADloadfunc p_load_func); +#endif + static bool is_gles_over_gl() { return gles_over_gl; } static void clear_depth(float p_depth); static void clear_stencil(int32_t p_stencil); diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index bc2597791a5d..8cda98c08881 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -38,6 +38,7 @@ #include "storage/mesh_storage.h" #include "storage/particles_storage.h" #include "storage/texture_storage.h" +#include "storage/utilities.h" #include "core/config/project_settings.h" #include "core/templates/sort_array.h" @@ -1048,7 +1049,7 @@ Ref RasterizerSceneGLES3::sky_bake_panorama(RID p_sky, float p_energy, bo GLuint rad_fbo = 0; glGenFramebuffers(1, &rad_fbo); - glBindFramebuffer(GL_FRAMEBUFFER, rad_fbo); + FramebufferBinding binding(GL_FRAMEBUFFER, rad_fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rad_tex, 0); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_CUBE_MAP, sky->radiance); @@ -1059,7 +1060,7 @@ Ref RasterizerSceneGLES3::sky_bake_panorama(RID p_sky, float p_energy, bo copy_effects->copy_cube_to_panorama(p_bake_irradiance ? float(sky->mipmap_count) : 0.0); - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); + binding.reset(); glDeleteFramebuffers(1, &rad_fbo); // Create a dummy texture so we can use texture_2d_get. RID tex_rid = GLES3::TextureStorage::get_singleton()->texture_allocate(); @@ -2193,7 +2194,7 @@ void RasterizerSceneGLES3::_render_shadow_pass(RID p_light, RID p_shadow_atlas, _fill_render_list(RENDER_LIST_SECONDARY, &render_data, PASS_MODE_SHADOW); render_list[RENDER_LIST_SECONDARY].sort_by_key(); - glBindFramebuffer(GL_FRAMEBUFFER, shadow_fb); + FramebufferBinding binding(GL_FRAMEBUFFER, shadow_fb); glViewport(atlas_rect.position.x, atlas_rect.position.y, atlas_rect.size.x, atlas_rect.size.y); GLuint global_buffer = GLES3::MaterialStorage::get_singleton()->global_shader_parameters_get_uniform_buffer(); @@ -2233,7 +2234,6 @@ void RasterizerSceneGLES3::_render_shadow_pass(RID p_light, RID p_shadow_atlas, scene_state.enable_gl_depth_draw(true); glDisable(GL_CULL_FACE); scene_state.cull_mode = RS::CULL_MODE_DISABLED; - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); } void RasterizerSceneGLES3::render_scene(const Ref &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray &p_instances, const PagedArray &p_lights, const PagedArray &p_reflection_probes, const PagedArray &p_voxel_gi_instances, const PagedArray &p_decals, const PagedArray &p_lightmaps, const PagedArray &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_compositor, 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) { @@ -3780,7 +3780,7 @@ void RasterizerSceneGLES3::render_particle_collider_heightfield(RID p_collider, RENDER_TIMESTAMP("Render Collider Heightfield"); - glBindFramebuffer(GL_FRAMEBUFFER, fb); + FramebufferBinding binding(GL_FRAMEBUFFER, fb); glViewport(0, 0, fb_size.width, fb_size.height); GLuint global_buffer = GLES3::MaterialStorage::get_singleton()->global_shader_parameters_get_uniform_buffer(); @@ -3805,7 +3805,6 @@ void RasterizerSceneGLES3::render_particle_collider_heightfield(RID p_collider, _render_list_template(&render_list_params, &render_data, 0, render_list[RENDER_LIST_SECONDARY].elements.size()); glColorMask(1, 1, 1, 1); - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); } void RasterizerSceneGLES3::_render_uv2(const PagedArray &p_instances, GLuint p_framebuffer, const Rect2i &p_region) { @@ -3826,7 +3825,7 @@ void RasterizerSceneGLES3::_render_uv2(const PagedArrayglobal_shader_parameters_get_uniform_buffer(); @@ -3887,7 +3886,6 @@ void RasterizerSceneGLES3::_render_uv2(const PagedArrayget_internal_size(); glViewport(0, 0, size.width, size.height); glBindTexture(GL_TEXTURE_2D, shadow_atlas_texture); copy_effects->copy_to_rect(Rect2(Vector2(), Vector2(0.5, 0.5))); glBindTexture(GL_TEXTURE_2D, 0); - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); } } if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS) { diff --git a/drivers/gles3/storage/light_storage.cpp b/drivers/gles3/storage/light_storage.cpp index f58f769b3e46..49c9ef35e6ed 100644 --- a/drivers/gles3/storage/light_storage.cpp +++ b/drivers/gles3/storage/light_storage.cpp @@ -827,6 +827,8 @@ bool LightStorage::reflection_probe_instance_begin_render(RID p_instance, RID p_ glActiveTexture(GL_TEXTURE0); + FramebufferBinding binding(GL_FRAMEBUFFER); + { // We create one set of 6 layers for depth, we can reuse this when rendering. glGenTextures(1, &atlas->depth); @@ -938,7 +940,6 @@ bool LightStorage::reflection_probe_instance_begin_render(RID p_instance, RID p_ } } - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); glBindTexture(GL_TEXTURE_CUBE_MAP, 0); glBindTexture(GL_TEXTURE_2D_ARRAY, 0); } @@ -1506,7 +1507,7 @@ bool LightStorage::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_i if (sc > (int)shadow_atlas->quadrants[qidx].textures.size()) { GLuint fbo_id = 0; glGenFramebuffers(1, &fbo_id); - glBindFramebuffer(GL_FRAMEBUFFER, fbo_id); + FramebufferBinding binding(GL_FRAMEBUFFER, fbo_id); GLuint texture_id = 0; glGenTextures(1, &texture_id); @@ -1559,7 +1560,6 @@ bool LightStorage::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_i glBindTexture(GL_TEXTURE_2D, 0); } - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); r_quadrant = qidx; r_shadow = shadow_atlas->quadrants[qidx].textures.size(); @@ -1629,6 +1629,7 @@ void LightStorage::shadow_atlas_update(RID p_atlas) { // Create if necessary and clear. void LightStorage::update_directional_shadow_atlas() { + FramebufferBinding binding(GL_FRAMEBUFFER); if (directional_shadow.depth == 0 && directional_shadow.size > 0) { glGenFramebuffers(1, &directional_shadow.fbo); glBindFramebuffer(GL_FRAMEBUFFER, directional_shadow.fbo); @@ -1659,7 +1660,6 @@ void LightStorage::update_directional_shadow_atlas() { glClear(GL_DEPTH_BUFFER_BIT); glBindTexture(GL_TEXTURE_2D, 0); - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); } void LightStorage::directional_shadow_atlas_set_size(int p_size, bool p_16_bits) { diff --git a/drivers/gles3/storage/light_storage.h b/drivers/gles3/storage/light_storage.h index 1e7dc195dbc7..d9c8e9096113 100644 --- a/drivers/gles3/storage/light_storage.h +++ b/drivers/gles3/storage/light_storage.h @@ -40,6 +40,7 @@ #include "drivers/gles3/storage/texture_storage.h" #include "servers/rendering/storage/light_storage.h" #include "servers/rendering/storage/utilities.h" +#include "utilities.h" namespace GLES3 { @@ -783,7 +784,7 @@ class LightStorage : public RendererLightStorage { return atlas->debug_fbo; } glGenFramebuffers(1, &atlas->debug_fbo); - glBindFramebuffer(GL_FRAMEBUFFER, atlas->debug_fbo); + FramebufferBinding binding(GL_FRAMEBUFFER, atlas->debug_fbo); if (atlas->debug_texture == 0) { atlas->debug_texture = shadow_atlas_get_debug_texture(p_atlas); @@ -794,8 +795,6 @@ class LightStorage : public RendererLightStorage { glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, atlas->debug_texture, 0); - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); - return atlas->debug_fbo; } diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp index 2d9b37192e0b..084a307c8695 100644 --- a/drivers/gles3/storage/mesh_storage.cpp +++ b/drivers/gles3/storage/mesh_storage.cpp @@ -1332,7 +1332,6 @@ void MeshStorage::update_mesh_instances() { } glEnable(GL_RASTERIZER_DISCARD); - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); // Process skeletons and blend shapes using transform feedback while (dirty_mesh_instance_arrays.first()) { MeshInstance *mi = dirty_mesh_instance_arrays.first()->self(); diff --git a/drivers/gles3/storage/particles_storage.cpp b/drivers/gles3/storage/particles_storage.cpp index bcdd0bee9b56..1eafec763c24 100644 --- a/drivers/gles3/storage/particles_storage.cpp +++ b/drivers/gles3/storage/particles_storage.cpp @@ -793,6 +793,8 @@ void ParticlesStorage::particles_set_view_axis(RID p_particles, const Vector3 &p Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_NULL(particles); + FramebufferBinding binding(GL_FRAMEBUFFER); + if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY) { return; } @@ -835,7 +837,7 @@ void ParticlesStorage::particles_set_view_axis(RID p_particles, const Vector3 &p } glEnable(GL_RASTERIZER_DISCARD); - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); + binding.reset(); _particles_update_instance_buffer(particles, axis, p_up_axis); glDisable(GL_RASTERIZER_DISCARD); } @@ -1025,7 +1027,6 @@ void ParticlesStorage::update_particles() { RENDER_TIMESTAMP("Update GPUParticles"); glEnable(GL_RASTERIZER_DISCARD); - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); GLuint global_buffer = GLES3::MaterialStorage::get_singleton()->global_shader_parameters_get_uniform_buffer(); @@ -1277,7 +1278,7 @@ GLuint ParticlesStorage::particles_collision_get_heightfield_framebuffer(RID p_p glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glGenFramebuffers(1, &particles_collision->heightfield_fb); - glBindFramebuffer(GL_FRAMEBUFFER, particles_collision->heightfield_fb); + FramebufferBinding binding(GL_FRAMEBUFFER, particles_collision->heightfield_fb); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, particles_collision->heightfield_texture, 0); #ifdef DEBUG_ENABLED GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); @@ -1290,7 +1291,6 @@ GLuint ParticlesStorage::particles_collision_get_heightfield_framebuffer(RID p_p particles_collision->heightfield_fb_size = size; glBindTexture(GL_TEXTURE_2D, 0); - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); } return particles_collision->heightfield_fb; diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.cpp b/drivers/gles3/storage/render_scene_buffers_gles3.cpp index 1ad5dc6bcbad..72c5a9e2d662 100644 --- a/drivers/gles3/storage/render_scene_buffers_gles3.cpp +++ b/drivers/gles3/storage/render_scene_buffers_gles3.cpp @@ -105,7 +105,7 @@ GLuint RenderSceneBuffersGLES3::_rt_get_cached_fbo(GLuint p_color, GLuint p_dept new_fbo.depth = p_depth; glGenFramebuffers(1, &new_fbo.fbo); - glBindFramebuffer(GL_FRAMEBUFFER, new_fbo.fbo); + FramebufferBinding binding(GL_FRAMEBUFFER, new_fbo.fbo); _rt_attach_textures(p_color, p_depth, p_samples, p_view_count, true); @@ -120,8 +120,6 @@ GLuint RenderSceneBuffersGLES3::_rt_get_cached_fbo(GLuint p_color, GLuint p_dept // cache it! msaa3d.cached_fbos.push_back(new_fbo); } - - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); #endif return new_fbo.fbo; @@ -246,7 +244,7 @@ void RenderSceneBuffersGLES3::_check_render_buffers() { // Create our internal 3D FBO. // Note that if MSAA is used and our rt_msaa_* extensions are available, this is only used for blitting and effects. glGenFramebuffers(1, &internal3d.fbo); - glBindFramebuffer(GL_FRAMEBUFFER, internal3d.fbo); + FramebufferBinding binding(GL_FRAMEBUFFER, internal3d.fbo); #ifndef IOS_ENABLED if (use_multiview) { @@ -267,7 +265,6 @@ void RenderSceneBuffersGLES3::_check_render_buffers() { } glBindTexture(texture_target, 0); - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); } if (msaa3d.mode != RS::VIEWPORT_MSAA_DISABLED && msaa3d.color == 0) { @@ -305,7 +302,7 @@ void RenderSceneBuffersGLES3::_check_render_buffers() { // Create our MSAA 3D FBO. glGenFramebuffers(1, &msaa3d.fbo); - glBindFramebuffer(GL_FRAMEBUFFER, msaa3d.fbo); + FramebufferBinding binding(GL_FRAMEBUFFER, msaa3d.fbo); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, msaa3d.color); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, msaa3d.depth); @@ -318,7 +315,6 @@ void RenderSceneBuffersGLES3::_check_render_buffers() { } glBindRenderbuffer(GL_RENDERBUFFER, 0); - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); #if !defined(IOS_ENABLED) && !defined(WEB_ENABLED) } else if (use_multiview && !config->rt_msaa_multiview_supported) { // Render to texture extensions not supported? fall back to MSAA textures through GL_EXT_multiview_texture_multisample. @@ -351,7 +347,7 @@ void RenderSceneBuffersGLES3::_check_render_buffers() { // Create our MSAA 3D FBO. glGenFramebuffers(1, &msaa3d.fbo); - glBindFramebuffer(GL_FRAMEBUFFER, msaa3d.fbo); + FramebufferBinding binding(GL_FRAMEBUFFER, msaa3d.fbo); glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, msaa3d.color, 0, 0, view_count); glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, msaa3d.depth, 0, 0, view_count); @@ -364,7 +360,6 @@ void RenderSceneBuffersGLES3::_check_render_buffers() { } glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, 0); - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); #endif #if defined(ANDROID_ENABLED) || defined(WEB_ENABLED) // Only supported on OpenGLES! } else if (!use_internal_buffer) { @@ -381,7 +376,7 @@ void RenderSceneBuffersGLES3::_check_render_buffers() { // We render to our internal textures, MSAA is only done in tile memory only. // On mobile this means MSAA never leaves tile memory = efficiency! glGenFramebuffers(1, &msaa3d.fbo); - glBindFramebuffer(GL_FRAMEBUFFER, msaa3d.fbo); + FramebufferBinding binding(GL_FRAMEBUFFER, msaa3d.fbo); _rt_attach_textures(internal3d.color, internal3d.depth, msaa3d.samples, view_count, true); @@ -391,8 +386,6 @@ void RenderSceneBuffersGLES3::_check_render_buffers() { msaa3d.mode = RS::VIEWPORT_MSAA_DISABLED; WARN_PRINT("Could not create 3D MSAA framebuffer, status: " + texture_storage->get_framebuffer_error(status)); } - - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); #endif } else { // HUH? how did we get here? @@ -471,7 +464,7 @@ void RenderSceneBuffersGLES3::check_backbuffer(bool p_need_color, bool p_need_de glGenFramebuffers(1, &backbuffer3d.fbo); } - glBindFramebuffer(GL_FRAMEBUFFER, backbuffer3d.fbo); + FramebufferBinding binding(GL_FRAMEBUFFER, backbuffer3d.fbo); bool use_multiview = view_count > 1 && GLES3::Config::get_singleton()->multiview_supported; GLenum texture_target = use_multiview ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D; @@ -541,7 +534,6 @@ void RenderSceneBuffersGLES3::check_backbuffer(bool p_need_color, bool p_need_de } glBindTexture(texture_target, 0); - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); } void RenderSceneBuffersGLES3::_clear_back_buffers() { @@ -571,6 +563,8 @@ void RenderSceneBuffersGLES3::check_glow_buffers() { return; } + FramebufferBinding binding(GL_FRAMEBUFFER); + GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton(); Size2i level_size = internal_size; for (int i = 0; i < 4; i++) { @@ -610,7 +604,6 @@ void RenderSceneBuffersGLES3::check_glow_buffers() { } glBindTexture(GL_TEXTURE_2D, 0); - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); } void RenderSceneBuffersGLES3::_clear_glow_buffers() { @@ -664,9 +657,8 @@ GLuint RenderSceneBuffersGLES3::get_render_fbo() { GLuint depth = texture_storage->render_target_get_depth(render_target); bool depth_has_stencil = texture_storage->render_target_get_depth_has_stencil(render_target); - glBindFramebuffer(GL_FRAMEBUFFER, rt_fbo); + FramebufferBinding binding(GL_FRAMEBUFFER, rt_fbo); _rt_attach_textures(color, depth, msaa3d.samples, view_count, depth_has_stencil); - glBindFramebuffer(GL_FRAMEBUFFER, texture_storage->system_fbo); } return rt_fbo; diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp index 3ad087474bfc..0ad22f386834 100644 --- a/drivers/gles3/storage/texture_storage.cpp +++ b/drivers/gles3/storage/texture_storage.cpp @@ -1201,7 +1201,7 @@ Ref TextureStorage::texture_2d_get(RID p_texture) const { GLuint temp_color_texture; glGenTextures(1, &temp_color_texture); - glBindFramebuffer(GL_FRAMEBUFFER, temp_framebuffer); + FramebufferBinding binding(GL_FRAMEBUFFER, temp_framebuffer); glBindTexture(GL_TEXTURE_2D, temp_color_texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->alloc_width, texture->alloc_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); @@ -1227,7 +1227,7 @@ Ref TextureStorage::texture_2d_get(RID p_texture) const { glReadPixels(0, 0, texture->alloc_width, texture->alloc_height, GL_RGBA, GL_UNSIGNED_BYTE, &w[0]); - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); + binding.reset(); glDeleteTextures(1, &temp_color_texture); glDeleteFramebuffers(1, &temp_framebuffer); @@ -1276,7 +1276,7 @@ Ref TextureStorage::texture_2d_layer_get(RID p_texture, int p_layer) cons GLuint temp_color_texture; glGenTextures(1, &temp_color_texture); - glBindFramebuffer(GL_FRAMEBUFFER, temp_framebuffer); + FramebufferBinding binding(GL_FRAMEBUFFER, temp_framebuffer); glBindTexture(GL_TEXTURE_2D, temp_color_texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->alloc_width, texture->alloc_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); @@ -1302,7 +1302,7 @@ Ref TextureStorage::texture_2d_layer_get(RID p_texture, int p_layer) cons glReadPixels(0, 0, texture->alloc_width, texture->alloc_height, GL_RGBA, GL_UNSIGNED_BYTE, &w[0]); - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); + binding.reset(); glDeleteTextures(1, &temp_color_texture); glDeleteFramebuffers(1, &temp_framebuffer); @@ -1388,7 +1388,7 @@ Vector> TextureStorage::texture_3d_get(RID p_texture) const { GLuint temp_color_texture; glGenTextures(1, &temp_color_texture); - glBindFramebuffer(GL_FRAMEBUFFER, temp_framebuffer); + FramebufferBinding binding(GL_FRAMEBUFFER, temp_framebuffer); glBindTexture(GL_TEXTURE_2D, temp_color_texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->alloc_width, texture->alloc_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); @@ -1408,7 +1408,7 @@ Vector> TextureStorage::texture_3d_get(RID p_texture) const { Vector> ret = _texture_3d_read_framebuffer(texture); - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); + binding.reset(); glDeleteTextures(1, &temp_color_texture); glDeleteFramebuffers(1, &temp_framebuffer); @@ -1934,6 +1934,8 @@ void TextureStorage::update_texture_atlas() { CopyEffects *copy_effects = CopyEffects::get_singleton(); ERR_FAIL_NULL(copy_effects); + FramebufferBinding binding(GL_FRAMEBUFFER); + if (!texture_atlas.dirty) { return; //nothing to do } @@ -2098,7 +2100,7 @@ void TextureStorage::update_texture_atlas() { copy_effects->copy_to_rect(t->uv_rect); } } - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); + binding.reset(); } /* DECAL API */ @@ -2143,17 +2145,17 @@ AABB TextureStorage::decal_get_aabb(RID p_decal) const { /* RENDER TARGET API */ -GLuint TextureStorage::system_fbo = 0; - void TextureStorage::_update_render_target(RenderTarget *rt) { // do not allocate a render target with no size if (rt->size.x <= 0 || rt->size.y <= 0) { return; } + FramebufferBinding binding(GL_FRAMEBUFFER); + // do not allocate a render target that is attached to the screen if (rt->direct_to_screen) { - rt->fbo = system_fbo; + rt->fbo = DisplayServer::get_singleton()->window_get_native_handle(DisplayServer::OPENGL_FBO, rt->direct_to_screen_id); return; } @@ -2314,7 +2316,7 @@ void TextureStorage::_update_render_target(RenderTarget *rt) { glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); - glBindFramebuffer(GL_FRAMEBUFFER, system_fbo); + binding.reset(); } void TextureStorage::_create_render_target_backbuffer(RenderTarget *rt) { @@ -2344,14 +2346,13 @@ void TextureStorage::_create_render_target_backbuffer(RenderTarget *rt) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, count - 1); glGenFramebuffers(1, &rt->backbuffer_fbo); - glBindFramebuffer(GL_FRAMEBUFFER, rt->backbuffer_fbo); + FramebufferBinding binding(GL_FRAMEBUFFER, rt->backbuffer_fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->backbuffer, 0); GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) { WARN_PRINT_ONCE("Cannot allocate mipmaps for canvas screen blur. Status: " + get_framebuffer_error(status)); - glBindFramebuffer(GL_FRAMEBUFFER, system_fbo); return; } GLES3::Utilities::get_singleton()->texture_allocated_data(rt->backbuffer, texture_size_bytes, "Render target backbuffer color texture"); @@ -2737,7 +2738,7 @@ bool TextureStorage::render_target_get_transparent(RID p_render_target) const { return rt->is_transparent; } -void TextureStorage::render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) { +void TextureStorage::render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen, DisplayServer::WindowID p_direct_to_screen_id) { RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_NULL(rt); @@ -2748,6 +2749,7 @@ void TextureStorage::render_target_set_direct_to_screen(RID p_render_target, boo // those functions change how they operate depending on the value of DIRECT_TO_SCREEN _clear_render_target(rt); rt->direct_to_screen = p_direct_to_screen; + rt->direct_to_screen_id = p_direct_to_screen_id; if (rt->direct_to_screen) { rt->overridden.color = RID(); rt->overridden.depth = RID(); @@ -2877,11 +2879,10 @@ void TextureStorage::render_target_do_clear_request(RID p_render_target) { if (!rt->clear_requested) { return; } - glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo); + FramebufferBinding binding(GL_FRAMEBUFFER, rt->fbo); glClearBufferfv(GL_COLOR, 0, rt->clear_color.components); rt->clear_requested = false; - glBindFramebuffer(GL_FRAMEBUFFER, system_fbo); } GLuint TextureStorage::render_target_get_fbo(RID p_render_target) const { @@ -3149,7 +3150,7 @@ void TextureStorage::render_target_sdf_process(RID p_render_target) { GLuint temp_fb; glGenFramebuffers(1, &temp_fb); - glBindFramebuffer(GL_FRAMEBUFFER, temp_fb); + FramebufferBinding binding(GL_FRAMEBUFFER, temp_fb); // Load CanvasSdfShaderGLES3::ShaderVariant variant = shrink ? CanvasSdfShaderGLES3::MODE_LOAD_SHRINK : CanvasSdfShaderGLES3::MODE_LOAD; @@ -3223,7 +3224,7 @@ void TextureStorage::render_target_sdf_process(RID p_render_target) { copy_effects->draw_screen_triangle(); glBindTexture(GL_TEXTURE_2D, 0); - glBindFramebuffer(GL_FRAMEBUFFER, system_fbo); + binding.reset(); glDeleteFramebuffers(1, &temp_fb); glDisable(GL_SCISSOR_TEST); } diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h index 52c98741aa8d..ccc5329b1b15 100644 --- a/drivers/gles3/storage/texture_storage.h +++ b/drivers/gles3/storage/texture_storage.h @@ -371,6 +371,7 @@ struct RenderTarget { bool is_transparent = false; bool direct_to_screen = false; + DisplayServer::WindowID direct_to_screen_id = DisplayServer::INVALID_WINDOW_ID; bool used_in_frame = false; RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED; @@ -625,8 +626,6 @@ class TextureStorage : public RendererTextureStorage { /* RENDER TARGET API */ - static GLuint system_fbo; - RenderTarget *get_render_target(RID p_rid) { return render_target_owner.get_or_null(p_rid); } bool owns_render_target(RID p_rid) { return render_target_owner.owns(p_rid); } @@ -641,7 +640,7 @@ class TextureStorage : public RendererTextureStorage { virtual Size2i render_target_get_size(RID p_render_target) const override; virtual void render_target_set_transparent(RID p_render_target, bool p_is_transparent) override; virtual bool render_target_get_transparent(RID p_render_target) const override; - virtual void render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) override; + virtual void render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen, DisplayServer::WindowID p_direct_to_screen_id) override; virtual bool render_target_get_direct_to_screen(RID p_render_target) const override; virtual bool render_target_was_used(RID p_render_target) const override; void render_target_clear_used(RID p_render_target); @@ -715,10 +714,6 @@ class TextureStorage : public RendererTextureStorage { glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); } - void bind_framebuffer_system() { - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); - } - String get_framebuffer_error(GLenum p_status); }; diff --git a/drivers/gles3/storage/utilities.h b/drivers/gles3/storage/utilities.h index 9e40d596df06..eda7ee083f80 100644 --- a/drivers/gles3/storage/utilities.h +++ b/drivers/gles3/storage/utilities.h @@ -36,6 +36,48 @@ #include "platform_gl.h" +class FramebufferBinding { +public: + FramebufferBinding(GLenum p_target) : + FramebufferBinding(p_target, 0, false) {} + + FramebufferBinding(GLenum p_target, GLuint p_framebuffer) : + FramebufferBinding(p_target, p_framebuffer, true) {} + + FramebufferBinding(GLenum p_target, GLuint p_framebuffer, bool p_bind) { + target = p_target; + GLenum binding_target; + switch (p_target) { + case GL_FRAMEBUFFER: + binding_target = GL_FRAMEBUFFER_BINDING; + break; + case GL_READ_FRAMEBUFFER: + binding_target = GL_READ_FRAMEBUFFER_BINDING; + break; + case GL_DRAW_FRAMEBUFFER: + binding_target = GL_DRAW_FRAMEBUFFER_BINDING; + break; + } + glGetIntegerv(binding_target, &framebuffer); + if (p_bind) { + glBindFramebuffer(p_target, p_framebuffer); + } + } + ~FramebufferBinding() { + reset(); + } + void reset() { + if (target != 0) { + glBindFramebuffer(target, framebuffer); + target = 0; + } + } + +private: + GLenum target = 0; + GLint framebuffer; +}; + namespace GLES3 { /* VISIBILITY NOTIFIER */ diff --git a/drivers/metal/metal_device_properties.mm b/drivers/metal/metal_device_properties.mm index 0cfe98e49ce0..869bc5f0612d 100644 --- a/drivers/metal/metal_device_properties.mm +++ b/drivers/metal/metal_device_properties.mm @@ -53,7 +53,9 @@ #include "servers/rendering/renderer_rd/effects/metal_fx.h" #import +#if !defined(IOS_SIMULATOR) #import +#endif #import #import @@ -134,6 +136,7 @@ features.needs_arg_encoders = !([p_device supportsFamily:MTLGPUFamilyMetal3] && features.argument_buffers_tier == MTLArgumentBuffersTier2); } +#if !defined(IOS_SIMULATOR) if (@available(macOS 13.0, iOS 16.0, tvOS 16.0, *)) { features.metal_fx_spatial = [MTLFXSpatialScalerDescriptor supportsDevice:p_device]; #ifdef METAL_MFXTEMPORAL_ENABLED @@ -142,6 +145,7 @@ features.metal_fx_temporal = false; #endif } +#endif MTLCompileOptions *opts = [MTLCompileOptions new]; features.mslVersionEnum = opts.languageVersion; // By default, Metal uses the most recent language version. diff --git a/drivers/metal/metal_objects.h b/drivers/metal/metal_objects.h index 4826ded95d69..7e349f405b28 100644 --- a/drivers/metal/metal_objects.h +++ b/drivers/metal/metal_objects.h @@ -882,7 +882,9 @@ class API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) MDRenderPipeline final : _FORCE_INLINE_ void apply(id __unsafe_unretained p_enc) const { [p_enc setCullMode:cull_mode]; [p_enc setTriangleFillMode:fill_mode]; +#if !defined(IOS_SIMULATOR) [p_enc setDepthClipMode:clip_mode]; +#endif [p_enc setFrontFacingWinding:winding]; depth_bias.apply(p_enc); stencil.apply(p_enc); diff --git a/drivers/metal/rendering_context_driver_metal.h b/drivers/metal/rendering_context_driver_metal.h index d2dd4958a991..206483a4e1d8 100644 --- a/drivers/metal/rendering_context_driver_metal.h +++ b/drivers/metal/rendering_context_driver_metal.h @@ -73,7 +73,7 @@ class API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) RenderingContextDriverMe bool device_supports_present(uint32_t p_device_index, SurfaceID p_surface) const final override { return true; } RenderingDeviceDriver *driver_create() final override; void driver_free(RenderingDeviceDriver *p_driver) final override; - SurfaceID surface_create(const void *p_platform_data) final override; + SurfaceID surface_create(Ref p_native_surface) final override; void surface_set_size(SurfaceID p_surface, uint32_t p_width, uint32_t p_height) final override; void surface_set_vsync_mode(SurfaceID p_surface, DisplayServer::VSyncMode p_vsync_mode) final override; DisplayServer::VSyncMode surface_get_vsync_mode(SurfaceID p_surface) const final override; @@ -86,15 +86,6 @@ class API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) RenderingContextDriverMe #pragma mark - Metal-specific methods - // Platform-specific data for the Windows embedded in this driver. - struct WindowPlatformData { -#ifdef __OBJC__ - CAMetalLayer *__unsafe_unretained layer; -#else - void *layer; -#endif - }; - class API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) Surface { protected: #ifdef __OBJC__ diff --git a/drivers/metal/rendering_context_driver_metal.mm b/drivers/metal/rendering_context_driver_metal.mm index 6871b97385fb..3a5ed2736e2f 100644 --- a/drivers/metal/rendering_context_driver_metal.mm +++ b/drivers/metal/rendering_context_driver_metal.mm @@ -30,6 +30,7 @@ #import "rendering_context_driver_metal.h" +#include "drivers/apple/rendering_native_surface_apple.h" #import "rendering_device_driver_metal.h" @protocol MTLDeviceEx @@ -44,12 +45,22 @@ - (void)setShouldMaximizeConcurrentCompilation:(BOOL)v; RenderingContextDriverMetal::~RenderingContextDriverMetal() { } +void mvkDispatchToMainAndWait(dispatch_block_t block) { + if (NSThread.isMainThread) { + block(); + } else { + dispatch_sync(dispatch_get_main_queue(), block); + } +} + Error RenderingContextDriverMetal::initialize() { if (OS::get_singleton()->get_environment("MTL_CAPTURE_ENABLED") == "1") { capture_available = true; } - metal_device = MTLCreateSystemDefaultDevice(); + mvkDispatchToMainAndWait(^{ + metal_device = MTLCreateSystemDefaultDevice(); + }); #if TARGET_OS_OSX if (@available(macOS 13.3, *)) { [id(metal_device) setShouldMaximizeConcurrentCompilation:YES]; @@ -99,6 +110,8 @@ class API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) SurfaceLayer : public Re layer.opaque = OS::get_singleton()->is_layered_allowed() ? NO : YES; layer.pixelFormat = get_pixel_format(); layer.device = p_device; + layer.minificationFilter = kCAFilterNearest; + layer.magnificationFilter = kCAFilterNearest; } ~SurfaceLayer() override { @@ -176,17 +189,25 @@ void present(MDCommandBuffer *p_cmd_buffer) override final { count--; front = (front + 1) % frame_buffers.size(); +#if !defined(IOS_SIMULATOR) if (vsync_mode != DisplayServer::VSYNC_DISABLED) { [p_cmd_buffer->get_command_buffer() presentDrawable:drawable afterMinimumDuration:present_minimum_duration]; - } else { + } else +#endif + { [p_cmd_buffer->get_command_buffer() presentDrawable:drawable]; } } }; -RenderingContextDriver::SurfaceID RenderingContextDriverMetal::surface_create(const void *p_platform_data) { - const WindowPlatformData *wpd = (const WindowPlatformData *)(p_platform_data); - Surface *surface = memnew(SurfaceLayer(wpd->layer, metal_device)); +RenderingContextDriver::SurfaceID RenderingContextDriverMetal::surface_create(Ref p_native_surface) { + Ref apple_native_surface = Object::cast_to(*p_native_surface); + ERR_FAIL_COND_V(apple_native_surface.is_null(), SurfaceID()); + + __block Surface *surface = nullptr; + mvkDispatchToMainAndWait(^{ + surface = memnew(SurfaceLayer((__bridge CAMetalLayer *)(void *)apple_native_surface->get_layer(), metal_device)); + }); return SurfaceID(surface); } diff --git a/drivers/metal/rendering_device_driver_metal.h b/drivers/metal/rendering_device_driver_metal.h index 09a3742925f3..e45d1ef517a6 100644 --- a/drivers/metal/rendering_device_driver_metal.h +++ b/drivers/metal/rendering_device_driver_metal.h @@ -165,6 +165,7 @@ class API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) RenderingDeviceDriverMet public: virtual FenceID fence_create() override final; virtual Error fence_wait(FenceID p_fence) override final; + virtual void frame_cleanup(FenceID p_fence) override final; virtual void fence_free(FenceID p_fence) override final; #pragma mark - Semaphores diff --git a/drivers/metal/rendering_device_driver_metal.mm b/drivers/metal/rendering_device_driver_metal.mm index 898785c31478..522b01f663e8 100644 --- a/drivers/metal/rendering_device_driver_metal.mm +++ b/drivers/metal/rendering_device_driver_metal.mm @@ -184,7 +184,11 @@ _FORCE_INLINE_ MTLSize mipmapLevelSizeFromSize(MTLSize p_size, NSUInteger p_leve MTLTextureTypeCube, MTLTextureType1DArray, MTLTextureType2DArray, +#if defined(IOS_SIMULATOR) + MTLTextureType2DArray, +#else MTLTextureTypeCubeArray, +#endif }; RenderingDeviceDriverMetal::Result RenderingDeviceDriverMetal::is_valid_linear(TextureFormat const &p_format) const { @@ -225,7 +229,11 @@ _FORCE_INLINE_ MTLSize mipmapLevelSizeFromSize(MTLSize p_size, NSUInteger p_leve p_format.texture_type == TEXTURE_TYPE_2D_ARRAY) { desc.arrayLength = p_format.array_layers; } else if (p_format.texture_type == TEXTURE_TYPE_CUBE_ARRAY) { +#if defined(IOS_SIMULATOR) + desc.arrayLength = p_format.array_layers; +#else desc.arrayLength = p_format.array_layers / 6; +#endif } // TODO(sgc): Evaluate lossy texture support (perhaps as a project option?) @@ -843,6 +851,9 @@ static const API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) MTLSamplerBorderC return FenceID(fence); } +void RenderingDeviceDriverMetal::frame_cleanup(FenceID p_fence) { +} + Error RenderingDeviceDriverMetal::fence_wait(FenceID p_fence) { Fence *fence = (Fence *)(p_fence.id); @@ -2948,6 +2959,7 @@ static MetalDeviceProfile device_profile_from_properties(MetalDeviceProperties * print_verbose("- Metal multiview not supported"); } +#if !defined(IOS_SIMULATOR) // The Metal renderer requires Apple4 family. This is 2017 era A11 chips and newer. if (device_properties->features.highestFamily < MTLGPUFamilyApple4) { String error_string = vformat("Your Apple GPU does not support the following features, which are required to use Metal-based renderers in Godot:\n\n"); @@ -2964,6 +2976,7 @@ static MetalDeviceProfile device_profile_from_properties(MetalDeviceProperties * return ERR_CANT_CREATE; } +#endif return OK; } diff --git a/drivers/register_driver_types.cpp b/drivers/register_driver_types.cpp index 55660ffe06f1..68473275c912 100644 --- a/drivers/register_driver_types.cpp +++ b/drivers/register_driver_types.cpp @@ -30,13 +30,20 @@ #include "register_driver_types.h" +#include "core/object/class_db.h" #include "drivers/png/image_loader_png.h" #include "drivers/png/resource_saver_png.h" +#include "drivers/vulkan/rendering_native_surface_vulkan.h" + static Ref image_loader_png; static Ref resource_saver_png; void register_core_driver_types() { +#ifdef VULKAN_ENABLED + GDREGISTER_ABSTRACT_CLASS(RenderingNativeSurfaceVulkan) +#endif + image_loader_png.instantiate(); ImageLoader::add_image_format_loader(image_loader_png); diff --git a/drivers/vulkan/rendering_context_driver_vulkan.cpp b/drivers/vulkan/rendering_context_driver_vulkan.cpp index f702cf233d7c..e15ed6b3106e 100644 --- a/drivers/vulkan/rendering_context_driver_vulkan.cpp +++ b/drivers/vulkan/rendering_context_driver_vulkan.cpp @@ -31,6 +31,8 @@ #ifdef VULKAN_ENABLED #include "rendering_context_driver_vulkan.h" +#include "rendering_native_surface_vulkan.h" +#include "servers/rendering/rendering_native_surface_external_target.h" #include "vk_enum_string_helper.h" @@ -388,7 +390,7 @@ RenderingContextDriverVulkan::~RenderingContextDriverVulkan() { } if (instance != VK_NULL_HANDLE) { - vkDestroyInstance(instance, get_allocation_callbacks(VK_OBJECT_TYPE_INSTANCE)); + functions.DestroyInstance(instance, get_allocation_callbacks(VK_OBJECT_TYPE_INSTANCE)); } } @@ -738,6 +740,18 @@ Error RenderingContextDriverVulkan::_initialize_instance() { volkLoadInstance(instance); #endif + functions.CreateDevice = PFN_vkCreateDevice(vkGetInstanceProcAddr(instance, "vkCreateDevice")); + functions.DestroyInstance = PFN_vkDestroyInstance(vkGetInstanceProcAddr(instance, "vkDestroyInstance")); + functions.DestroySurfaceKHR = PFN_vkDestroySurfaceKHR(vkGetInstanceProcAddr(instance, "vkDestroySurfaceKHR")); + functions.EnumerateDeviceExtensionProperties = PFN_vkEnumerateDeviceExtensionProperties(vkGetInstanceProcAddr(instance, "vkEnumerateDeviceExtensionProperties")); + functions.EnumeratePhysicalDevices = PFN_vkEnumeratePhysicalDevices(vkGetInstanceProcAddr(instance, "vkEnumeratePhysicalDevices")); + functions.GetPhysicalDeviceFeatures = PFN_vkGetPhysicalDeviceFeatures(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures")); + functions.GetPhysicalDeviceMemoryProperties = PFN_vkGetPhysicalDeviceMemoryProperties(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceMemoryProperties")); + functions.GetPhysicalDeviceProperties = PFN_vkGetPhysicalDeviceProperties(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties")); + functions.GetPhysicalDeviceQueueFamilyProperties = PFN_vkGetPhysicalDeviceQueueFamilyProperties(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceQueueFamilyProperties")); + functions.GetPhysicalDeviceFormatProperties = PFN_vkGetPhysicalDeviceFormatProperties(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFormatProperties")); + functions.EnumerateInstanceLayerProperties = PFN_vkEnumerateInstanceLayerProperties(vkGetInstanceProcAddr(instance, "vkEnumerateInstanceLayerProperties")); + // Physical device. if (enabled_instance_extension_names.has(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) { functions.GetPhysicalDeviceFeatures2 = PFN_vkGetPhysicalDeviceFeatures2(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2")); @@ -770,6 +784,7 @@ Error RenderingContextDriverVulkan::_initialize_instance() { functions.CmdBeginDebugUtilsLabelEXT = (PFN_vkCmdBeginDebugUtilsLabelEXT)vkGetInstanceProcAddr(instance, "vkCmdBeginDebugUtilsLabelEXT"); functions.CmdEndDebugUtilsLabelEXT = (PFN_vkCmdEndDebugUtilsLabelEXT)vkGetInstanceProcAddr(instance, "vkCmdEndDebugUtilsLabelEXT"); functions.SetDebugUtilsObjectNameEXT = (PFN_vkSetDebugUtilsObjectNameEXT)vkGetInstanceProcAddr(instance, "vkSetDebugUtilsObjectNameEXT"); + functions.SubmitDebugUtilsMessageEXT = (PFN_vkSubmitDebugUtilsMessageEXT)vkGetInstanceProcAddr(instance, "vkSubmitDebugUtilsMessageEXT"); if (!functions.debug_util_functions_available()) { ERR_FAIL_V_MSG(ERR_CANT_CREATE, "GetProcAddr: Failed to init VK_EXT_debug_utils\nGetProcAddr: Failure"); @@ -825,21 +840,21 @@ Error RenderingContextDriverVulkan::_initialize_devices() { } else { uint32_t physical_device_count = 0; - VkResult err = vkEnumeratePhysicalDevices(instance, &physical_device_count, nullptr); + VkResult err = functions.EnumeratePhysicalDevices(instance, &physical_device_count, nullptr); ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE); ERR_FAIL_COND_V_MSG(physical_device_count == 0, ERR_CANT_CREATE, "vkEnumeratePhysicalDevices reported zero accessible devices.\n\nDo you have a compatible Vulkan installable client driver (ICD) installed?\nvkEnumeratePhysicalDevices Failure."); driver_devices.resize(physical_device_count); physical_devices.resize(physical_device_count); device_queue_families.resize(physical_device_count); - err = vkEnumeratePhysicalDevices(instance, &physical_device_count, physical_devices.ptr()); + err = functions.EnumeratePhysicalDevices(instance, &physical_device_count, physical_devices.ptr()); ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE); } // Fill the list of driver devices with the properties from the physical devices. for (uint32_t i = 0; i < physical_devices.size(); i++) { VkPhysicalDeviceProperties props; - vkGetPhysicalDeviceProperties(physical_devices[i], &props); + functions.GetPhysicalDeviceProperties(physical_devices[i], &props); Device &driver_device = driver_devices[i]; driver_device.name = String::utf8(props.deviceName); @@ -850,11 +865,11 @@ Error RenderingContextDriverVulkan::_initialize_devices() { _check_driver_workarounds(props, driver_device); uint32_t queue_family_properties_count = 0; - vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &queue_family_properties_count, nullptr); + functions.GetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &queue_family_properties_count, nullptr); if (queue_family_properties_count > 0) { device_queue_families[i].properties.resize(queue_family_properties_count); - vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &queue_family_properties_count, device_queue_families[i].properties.ptr()); + functions.GetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &queue_family_properties_count, device_queue_families[i].properties.ptr()); } } @@ -968,9 +983,28 @@ void RenderingContextDriverVulkan::driver_free(RenderingDeviceDriver *p_driver) memdelete(p_driver); } -RenderingContextDriver::SurfaceID RenderingContextDriverVulkan::surface_create(const void *p_platform_data) { - DEV_ASSERT(false && "Surface creation should not be called on the platform-agnostic version of the driver."); - return SurfaceID(); +RenderingContextDriver::SurfaceID RenderingContextDriverVulkan::surface_create(Ref p_native_surface) { +#ifdef EXTERNAL_TARGET_ENABLED + Ref external_native_surface = Object::cast_to(*p_native_surface); + if (external_native_surface.is_valid()) { + Surface *surface = memnew(Surface); + surface->headless = true; + surface->width = external_native_surface->get_width(); + surface->height = external_native_surface->get_height(); + surface->needs_resize = true; + + SurfaceID surface_id = SurfaceID(surface); + external_native_surface->set_surface(surface_id); + return surface_id; + } +#endif + + Ref vulkan_native_surface = Object::cast_to(*p_native_surface); + ERR_FAIL_COND_V(vulkan_native_surface == nullptr, SurfaceID()); + + Surface *surface = memnew(Surface); + surface->vk_surface = vulkan_native_surface->get_vulkan_surface(); + return SurfaceID(surface); } void RenderingContextDriverVulkan::surface_set_size(SurfaceID p_surface, uint32_t p_width, uint32_t p_height) { @@ -1013,7 +1047,16 @@ bool RenderingContextDriverVulkan::surface_get_needs_resize(SurfaceID p_surface) void RenderingContextDriverVulkan::surface_destroy(SurfaceID p_surface) { Surface *surface = (Surface *)(p_surface); - vkDestroySurfaceKHR(instance, surface->vk_surface, get_allocation_callbacks(VK_OBJECT_TYPE_SURFACE_KHR)); + +#ifdef EXTERNAL_TARGET_ENABLED + const bool should_destroy_surface = !surface->headless; +#else + const bool should_destroy_surface = true; +#endif + if (should_destroy_surface) { + functions.DestroySurfaceKHR(instance, surface->vk_surface, get_allocation_callbacks(VK_OBJECT_TYPE_SURFACE_KHR)); + } + memdelete(surface); } @@ -1021,6 +1064,10 @@ bool RenderingContextDriverVulkan::is_debug_utils_enabled() const { return enabled_instance_extension_names.has(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); } +bool RenderingContextDriverVulkan::is_extension_enabled(const CharString &p_extension_name) const { + return enabled_instance_extension_names.has(p_extension_name); +} + VkInstance RenderingContextDriverVulkan::instance_get() const { return instance; } @@ -1046,7 +1093,12 @@ bool RenderingContextDriverVulkan::queue_family_supports_present(VkPhysicalDevic DEV_ASSERT(p_surface != 0); Surface *surface = (Surface *)(p_surface); VkBool32 present_supported = false; - VkResult err = vkGetPhysicalDeviceSurfaceSupportKHR(p_physical_device, p_queue_family_index, surface->vk_surface, &present_supported); + VkResult err = VK_SUCCESS; + if (surface->vk_surface) { + err = functions.GetPhysicalDeviceSurfaceSupportKHR(p_physical_device, p_queue_family_index, surface->vk_surface, &present_supported); + } else { + present_supported = true; + } return err == VK_SUCCESS && present_supported; } diff --git a/drivers/vulkan/rendering_context_driver_vulkan.h b/drivers/vulkan/rendering_context_driver_vulkan.h index 2881a17cb7bb..fcbfbdba689b 100644 --- a/drivers/vulkan/rendering_context_driver_vulkan.h +++ b/drivers/vulkan/rendering_context_driver_vulkan.h @@ -46,16 +46,29 @@ class RenderingContextDriverVulkan : public RenderingContextDriver { struct Functions { // Physical device. PFN_vkGetPhysicalDeviceFeatures2 GetPhysicalDeviceFeatures2 = nullptr; + PFN_vkGetPhysicalDeviceProperties GetPhysicalDeviceProperties = nullptr; PFN_vkGetPhysicalDeviceProperties2 GetPhysicalDeviceProperties2 = nullptr; // Device. + PFN_vkCreateDevice CreateDevice = nullptr; PFN_vkGetDeviceProcAddr GetDeviceProcAddr = nullptr; + PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties = nullptr; + PFN_vkEnumeratePhysicalDevices EnumeratePhysicalDevices = nullptr; + PFN_vkGetPhysicalDeviceFeatures GetPhysicalDeviceFeatures = nullptr; + PFN_vkGetPhysicalDeviceMemoryProperties GetPhysicalDeviceMemoryProperties = nullptr; + PFN_vkGetPhysicalDeviceQueueFamilyProperties GetPhysicalDeviceQueueFamilyProperties = nullptr; + PFN_vkGetPhysicalDeviceFormatProperties GetPhysicalDeviceFormatProperties = nullptr; // Surfaces. PFN_vkGetPhysicalDeviceSurfaceSupportKHR GetPhysicalDeviceSurfaceSupportKHR = nullptr; PFN_vkGetPhysicalDeviceSurfaceFormatsKHR GetPhysicalDeviceSurfaceFormatsKHR = nullptr; PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR GetPhysicalDeviceSurfaceCapabilitiesKHR = nullptr; PFN_vkGetPhysicalDeviceSurfacePresentModesKHR GetPhysicalDeviceSurfacePresentModesKHR = nullptr; + PFN_vkDestroySurfaceKHR DestroySurfaceKHR = nullptr; + + // Instance. + PFN_vkDestroyInstance DestroyInstance = nullptr; + PFN_vkEnumerateInstanceLayerProperties EnumerateInstanceLayerProperties = nullptr; // Debug utils. PFN_vkCreateDebugUtilsMessengerEXT CreateDebugUtilsMessengerEXT = nullptr; @@ -63,6 +76,7 @@ class RenderingContextDriverVulkan : public RenderingContextDriver { PFN_vkCmdBeginDebugUtilsLabelEXT CmdBeginDebugUtilsLabelEXT = nullptr; PFN_vkCmdEndDebugUtilsLabelEXT CmdEndDebugUtilsLabelEXT = nullptr; PFN_vkSetDebugUtilsObjectNameEXT SetDebugUtilsObjectNameEXT = nullptr; + PFN_vkSubmitDebugUtilsMessageEXT SubmitDebugUtilsMessageEXT = nullptr; bool debug_util_functions_available() const { return CreateDebugUtilsMessengerEXT != nullptr && @@ -134,7 +148,7 @@ class RenderingContextDriverVulkan : public RenderingContextDriver { virtual bool device_supports_present(uint32_t p_device_index, SurfaceID p_surface) const override; virtual RenderingDeviceDriver *driver_create() override; virtual void driver_free(RenderingDeviceDriver *p_driver) override; - virtual SurfaceID surface_create(const void *p_platform_data) override; + virtual SurfaceID surface_create(Ref p_native_surface) override; virtual void surface_set_size(SurfaceID p_surface, uint32_t p_width, uint32_t p_height) override; virtual void surface_set_vsync_mode(SurfaceID p_surface, DisplayServer::VSyncMode p_vsync_mode) override; virtual DisplayServer::VSyncMode surface_get_vsync_mode(SurfaceID p_surface) const override; @@ -144,10 +158,12 @@ class RenderingContextDriverVulkan : public RenderingContextDriver { virtual bool surface_get_needs_resize(SurfaceID p_surface) const override; virtual void surface_destroy(SurfaceID p_surface) override; virtual bool is_debug_utils_enabled() const override; + bool is_extension_enabled(const CharString &p_extension_name) const; // Vulkan-only methods. struct Surface { VkSurfaceKHR vk_surface = VK_NULL_HANDLE; + bool headless = false; // For headless surfaces we create an emulated swapchain with images and synchronizations uint32_t width = 0; uint32_t height = 0; DisplayServer::VSyncMode vsync_mode = DisplayServer::VSYNC_ENABLED; diff --git a/drivers/vulkan/rendering_device_driver_vulkan.cpp b/drivers/vulkan/rendering_device_driver_vulkan.cpp index d2a7ffd1fc6a..cf8bed197ccd 100644 --- a/drivers/vulkan/rendering_device_driver_vulkan.cpp +++ b/drivers/vulkan/rendering_device_driver_vulkan.cpp @@ -46,6 +46,19 @@ #include "thirdparty/swappy-frame-pacing/swappyVk.h" #endif +#include "thirdparty/vulkan/vk_enum_string_helper.h" + +#if defined(UNIX_ENABLED) +#include +#endif + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__) +#include +#undef CreateSemaphore +#undef MemoryBarrier +#include +#endif + #define ARRAY_SIZE(a) std::size(a) #define PRINT_NATIVE_COMMANDS 0 @@ -524,6 +537,7 @@ Error RenderingDeviceDriverVulkan::_initialize_device_extensions() { _register_requested_device_extension(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME, false); _register_requested_device_extension(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, false); _register_requested_device_extension(VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME, false); + _register_requested_device_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, false); _register_requested_device_extension(VK_KHR_16BIT_STORAGE_EXTENSION_NAME, false); _register_requested_device_extension(VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME, false); _register_requested_device_extension(VK_KHR_MAINTENANCE_2_EXTENSION_NAME, false); @@ -533,10 +547,16 @@ Error RenderingDeviceDriverVulkan::_initialize_device_extensions() { _register_requested_device_extension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME, false); _register_requested_device_extension(VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME, false); _register_requested_device_extension(VK_EXT_TEXTURE_COMPRESSION_ASTC_HDR_EXTENSION_NAME, false); - - // We don't actually use this extension, but some runtime components on some platforms - // can and will fill the validation layers with useless info otherwise if not enabled. + _register_requested_device_extension(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME, true); +#ifdef EXTERNAL_TARGET_ENABLED +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__) + _register_requested_device_extension(VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME, true); +#elif defined(UNIX_ENABLED) + _register_requested_device_extension(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, true); +#endif +#else _register_requested_device_extension(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, false); +#endif if (Engine::get_singleton()->is_generate_spirv_debug_info_enabled()) { _register_requested_device_extension(VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME, true); @@ -564,13 +584,13 @@ Error RenderingDeviceDriverVulkan::_initialize_device_extensions() { uint32_t device_extension_count = 0; VkResult err = vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &device_extension_count, nullptr); - ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE); + ERR_FAIL_COND_V_MSG(err != VK_SUCCESS, ERR_CANT_CREATE, string_VkResult(err)); ERR_FAIL_COND_V_MSG(device_extension_count == 0, ERR_CANT_CREATE, "vkEnumerateDeviceExtensionProperties failed to find any extensions\n\nDo you have a compatible Vulkan installable client driver (ICD) installed?"); TightLocalVector device_extensions; device_extensions.resize(device_extension_count); err = vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &device_extension_count, device_extensions.ptr()); - ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE); + ERR_FAIL_COND_V_MSG(err != VK_SUCCESS, ERR_CANT_CREATE, string_VkResult(err)); #if defined(SWAPPY_FRAME_PACING_ENABLED) if (swappy_frame_pacer_enable) { @@ -1020,6 +1040,9 @@ Error RenderingDeviceDriverVulkan::_check_device_capabilities() { if (subgroup_capabilities.quad_operations_in_all_stages) { print_verbose(" quad operations in all stages"); } + + // Get Memory information and properties. + context_driver->functions_get().GetPhysicalDeviceMemoryProperties(physical_device, &memory_properties); } return OK; @@ -1204,7 +1227,7 @@ Error RenderingDeviceDriverVulkan::_initialize_device(const LocalVectorimage_semaphores_swap_chains[p_semaphore_index]; if (swap_chain != nullptr) { @@ -1378,17 +1418,8 @@ bool RenderingDeviceDriverVulkan::_release_image_semaphore(CommandQueue *p_comma p_command_queue->image_semaphores_swap_chains[p_semaphore_index] = nullptr; if (p_release_on_swap_chain) { - // Remove the acquired semaphore from the swap chain's vectors. - for (uint32_t i = 0; i < swap_chain->command_queues_acquired.size(); i++) { - if (swap_chain->command_queues_acquired[i] == p_command_queue && swap_chain->command_queues_acquired_semaphores[i] == p_semaphore_index) { - swap_chain->command_queues_acquired.remove_at(i); - swap_chain->command_queues_acquired_semaphores.remove_at(i); - break; - } - } + return swap_chain->release_image_semaphore(p_command_queue, p_semaphore_index); } - - return true; } return false; @@ -1401,7 +1432,7 @@ bool RenderingDeviceDriverVulkan::_recreate_image_semaphore(CommandQueue *p_comm VkSemaphoreCreateInfo create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; VkResult err = vkCreateSemaphore(vk_device, &create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SEMAPHORE), &semaphore); - ERR_FAIL_COND_V(err != VK_SUCCESS, false); + ERR_FAIL_COND_V_MSG(err != VK_SUCCESS, false, string_VkResult(err)); // Indicate the semaphore is free again and destroy the previous one before storing the new one. vkDestroySemaphore(vk_device, p_command_queue->image_semaphores[p_semaphore_index], VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SEMAPHORE)); @@ -1524,7 +1555,8 @@ void RenderingDeviceDriverVulkan::_set_object_name(VkObjectType p_object_type, u Error RenderingDeviceDriverVulkan::initialize(uint32_t p_device_index, uint32_t p_frame_count) { context_device = context_driver->device_get(p_device_index); physical_device = context_driver->physical_device_get(p_device_index); - vkGetPhysicalDeviceProperties(physical_device, &physical_device_properties); + const RenderingContextDriverVulkan::Functions &functions = context_driver->functions_get(); + functions.GetPhysicalDeviceProperties(physical_device, &physical_device_properties); // Workaround a driver bug on Adreno 730 GPUs that keeps leaking memory on each call to vkResetDescriptorPool. // Which eventually run out of memory. In such case we should not be using linear allocated pools @@ -2089,7 +2121,8 @@ RDD::TextureID RenderingDeviceDriverVulkan::texture_create_shared(TextureID p_or // Certain features may not be available for the format of the view. { VkFormatProperties properties = {}; - vkGetPhysicalDeviceFormatProperties(physical_device, RD_TO_VK_FORMAT[p_view.format], &properties); + const RenderingContextDriverVulkan::Functions &functions = context_driver->functions_get(); + functions.GetPhysicalDeviceFormatProperties(physical_device, RD_TO_VK_FORMAT[p_view.format], &properties); const VkFormatFeatureFlags &supported_flags = owner_tex_info->vk_create_info.tiling == VK_IMAGE_TILING_LINEAR ? properties.linearTilingFeatures : properties.optimalTilingFeatures; if ((usage_info->usage & VK_IMAGE_USAGE_STORAGE_BIT) && !(supported_flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) { usage_info->usage &= ~uint32_t(VK_IMAGE_USAGE_STORAGE_BIT); @@ -2272,7 +2305,8 @@ BitField RenderingDeviceDriverVulkan::texture_get_usages_ return 0; } VkFormatProperties properties = {}; - vkGetPhysicalDeviceFormatProperties(physical_device, RD_TO_VK_FORMAT[p_format], &properties); + const RenderingContextDriverVulkan::Functions &functions = context_driver->functions_get(); + functions.GetPhysicalDeviceFormatProperties(physical_device, RD_TO_VK_FORMAT[p_format], &properties); const VkFormatFeatureFlags &flags = p_cpu_readable ? properties.linearTilingFeatures : properties.optimalTilingFeatures; @@ -2364,7 +2398,8 @@ bool RenderingDeviceDriverVulkan::sampler_is_format_supported_for_filter(DataFor } case SAMPLER_FILTER_LINEAR: { VkFormatProperties properties = {}; - vkGetPhysicalDeviceFormatProperties(physical_device, RD_TO_VK_FORMAT[p_format], &properties); + const RenderingContextDriverVulkan::Functions &functions = context_driver->functions_get(); + functions.GetPhysicalDeviceFormatProperties(physical_device, RD_TO_VK_FORMAT[p_format], &properties); return (properties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT); } } @@ -2534,7 +2569,7 @@ RDD::FenceID RenderingDeviceDriverVulkan::fence_create() { VkFenceCreateInfo create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; VkResult err = vkCreateFence(vk_device, &create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_FENCE), &vk_fence); - ERR_FAIL_COND_V(err != VK_SUCCESS, FenceID()); + ERR_FAIL_COND_V_MSG(err != VK_SUCCESS, FenceID(), string_VkResult(err)); Fence *fence = memnew(Fence); fence->vk_fence = vk_fence; @@ -2547,12 +2582,17 @@ Error RenderingDeviceDriverVulkan::fence_wait(FenceID p_fence) { VkResult fence_status = vkGetFenceStatus(vk_device, fence->vk_fence); if (fence_status == VK_NOT_READY) { VkResult err = vkWaitForFences(vk_device, 1, &fence->vk_fence, VK_TRUE, UINT64_MAX); - ERR_FAIL_COND_V(err != VK_SUCCESS, FAILED); + ERR_FAIL_COND_V_MSG(err != VK_SUCCESS, FAILED, string_VkResult(err)); } VkResult err = vkResetFences(vk_device, 1, &fence->vk_fence); - ERR_FAIL_COND_V(err != VK_SUCCESS, FAILED); + ERR_FAIL_COND_V_MSG(err != VK_SUCCESS, FAILED, string_VkResult(err)); + return OK; +} + +void RenderingDeviceDriverVulkan::frame_cleanup(FenceID p_fence) { + Fence *fence = (Fence *)(p_fence.id); if (fence->queue_signaled_from != nullptr) { // Release all semaphores that the command queue associated to the fence waited on the last time it was submitted. LocalVector> &pairs = fence->queue_signaled_from->image_semaphores_for_fences; @@ -2569,8 +2609,6 @@ Error RenderingDeviceDriverVulkan::fence_wait(FenceID p_fence) { fence->queue_signaled_from = nullptr; } - - return OK; } void RenderingDeviceDriverVulkan::fence_free(FenceID p_fence) { @@ -2588,7 +2626,7 @@ RDD::SemaphoreID RenderingDeviceDriverVulkan::semaphore_create() { VkSemaphoreCreateInfo create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; VkResult err = vkCreateSemaphore(vk_device, &create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SEMAPHORE), &semaphore); - ERR_FAIL_COND_V(err != VK_SUCCESS, SemaphoreID()); + ERR_FAIL_COND_V_MSG(err != VK_SUCCESS, SemaphoreID(), string_VkResult(err)); return SemaphoreID(semaphore); } @@ -2708,6 +2746,23 @@ Error RenderingDeviceDriverVulkan::command_queue_execute_and_present(CommandQueu wait_semaphores_stages.push_back(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); } + thread_local LocalVector swapchains; + thread_local LocalVector presented_swapchains; + thread_local LocalVector image_indices; + swapchains.clear(); + presented_swapchains.clear(); + image_indices.clear(); + + for (uint32_t i = 0; i < p_swap_chains.size(); i++) { + SwapChain *swap_chain = (SwapChain *)(p_swap_chains[i].id); + if (VkSwapchainKHR swap_chain_handle = swap_chain->get_swapchain_handle()) { + swapchains.push_back(swap_chain_handle); + presented_swapchains.push_back(swap_chain); + DEV_ASSERT(swap_chain->get_image_index() < swap_chain->get_number_of_images()); + image_indices.push_back(swap_chain->get_image_index()); + } + } + if (p_cmd_buffers.size() > 0) { thread_local LocalVector command_buffers; thread_local LocalVector present_semaphores; @@ -2725,9 +2780,9 @@ Error RenderingDeviceDriverVulkan::command_queue_execute_and_present(CommandQueu signal_semaphores.push_back(VkSemaphore(p_cmd_semaphores[i].id)); } - for (uint32_t i = 0; i < p_swap_chains.size(); i++) { - const SwapChain *swap_chain = (const SwapChain *)(p_swap_chains[i].id); - VkSemaphore semaphore = swap_chain->present_semaphores[swap_chain->image_index]; + for (uint32_t i = 0; i < presented_swapchains.size(); i++) { + const SwapChain *swap_chain = presented_swapchains[i]; + VkSemaphore semaphore = swap_chain->get_present_semaphore(swap_chain->get_image_index()); present_semaphores.push_back(semaphore); signal_semaphores.push_back(semaphore); } @@ -2750,7 +2805,7 @@ Error RenderingDeviceDriverVulkan::command_queue_execute_and_present(CommandQueu print_lost_device_info(); CRASH_NOW_MSG("Vulkan device was lost."); } - ERR_FAIL_COND_V(err != VK_SUCCESS, FAILED); + ERR_FAIL_COND_V_MSG(err != VK_SUCCESS, FAILED, string_VkResult(err)); if (fence != nullptr && !command_queue->pending_semaphores_for_fence.is_empty()) { fence->queue_signaled_from = command_queue; @@ -2769,19 +2824,8 @@ Error RenderingDeviceDriverVulkan::command_queue_execute_and_present(CommandQueu } } - if (p_swap_chains.size() > 0) { - thread_local LocalVector swapchains; - thread_local LocalVector image_indices; + if (swapchains.size() > 0) { thread_local LocalVector results; - swapchains.clear(); - image_indices.clear(); - - for (uint32_t i = 0; i < p_swap_chains.size(); i++) { - SwapChain *swap_chain = (SwapChain *)(p_swap_chains[i].id); - swapchains.push_back(swap_chain->vk_swapchain); - DEV_ASSERT(swap_chain->image_index < swap_chain->images.size()); - image_indices.push_back(swap_chain->image_index); - } results.resize(swapchains.size()); @@ -2809,11 +2853,11 @@ Error RenderingDeviceDriverVulkan::command_queue_execute_and_present(CommandQueu // Set the index to an invalid value. If any of the swap chains returned out of date, indicate it should be resized the next time it's acquired. bool any_result_is_out_of_date = false; - for (uint32_t i = 0; i < p_swap_chains.size(); i++) { - SwapChain *swap_chain = (SwapChain *)(p_swap_chains[i].id); - swap_chain->image_index = UINT_MAX; + for (uint32_t i = 0; i < presented_swapchains.size(); i++) { + SwapChain *swap_chain = presented_swapchains[i]; + swap_chain->set_image_index(UINT_MAX); if (results[i] == VK_ERROR_OUT_OF_DATE_KHR) { - context_driver->surface_set_needs_resize(swap_chain->surface, true); + context_driver->surface_set_needs_resize(swap_chain->get_surface(), true); any_result_is_out_of_date = true; } } @@ -2997,47 +3041,147 @@ void RenderingDeviceDriverVulkan::command_buffer_execute_secondary(CommandBuffer /**** SWAP CHAIN ****/ /********************/ -void RenderingDeviceDriverVulkan::_swap_chain_release(SwapChain *swap_chain) { +void RenderingDeviceDriverVulkan::PresentableSwapChain::release() { // Destroy views and framebuffers associated to the swapchain's images. - for (FramebufferID framebuffer : swap_chain->framebuffers) { - framebuffer_free(framebuffer); + + { + MutexLock external_lock(mutex); + + if (!in_use.is_empty()) { + in_use.clear(); + } + + last_drawn_buffer = -1; + version += 1; + } + + for (FramebufferID framebuffer : framebuffers) { + device_driver->framebuffer_free(framebuffer); } - for (VkImageView view : swap_chain->image_views) { - vkDestroyImageView(vk_device, view, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_IMAGE_VIEW)); + for (VkImageView view : image_views) { + vkDestroyImageView(device_driver->vk_device, view, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_IMAGE_VIEW)); } - swap_chain->image_index = UINT_MAX; - swap_chain->images.clear(); - swap_chain->image_views.clear(); - swap_chain->framebuffers.clear(); + image_index = UINT_MAX; + images.clear(); + image_views.clear(); + framebuffers.clear(); - if (swap_chain->vk_swapchain != VK_NULL_HANDLE) { + if (vk_swapchain != VK_NULL_HANDLE) { #if defined(SWAPPY_FRAME_PACING_ENABLED) if (swappy_frame_pacer_enable) { // Swappy has a bug where the ANativeWindow will be leaked if we call // SwappyVk_destroySwapchain, so we must release it by hand. - SwappyVk_setWindow(vk_device, swap_chain->vk_swapchain, nullptr); - SwappyVk_destroySwapchain(vk_device, swap_chain->vk_swapchain); + SwappyVk_setWindow(device_driver->vk_device, vk_swapchain, nullptr); + SwappyVk_destroySwapchain(device_driver->vk_device, vk_swapchain); } #endif - device_functions.DestroySwapchainKHR(vk_device, swap_chain->vk_swapchain, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SWAPCHAIN_KHR)); - swap_chain->vk_swapchain = VK_NULL_HANDLE; + device_driver->device_functions.DestroySwapchainKHR(device_driver->vk_device, vk_swapchain, nullptr); + vk_swapchain = VK_NULL_HANDLE; } - for (uint32_t i = 0; i < swap_chain->command_queues_acquired.size(); i++) { - _recreate_image_semaphore(swap_chain->command_queues_acquired[i], swap_chain->command_queues_acquired_semaphores[i], false); + for (uint32_t i = 0; i < command_queues_acquired.size(); i++) { + device_driver->_recreate_image_semaphore(command_queues_acquired[i], command_queues_acquired_semaphores[i], false); } - swap_chain->command_queues_acquired.clear(); - swap_chain->command_queues_acquired_semaphores.clear(); + command_queues_acquired.clear(); + command_queues_acquired_semaphores.clear(); - for (VkSemaphore semaphore : swap_chain->present_semaphores) { - vkDestroySemaphore(vk_device, semaphore, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SEMAPHORE)); + for (VkSemaphore semaphore : present_semaphores) { + vkDestroySemaphore(device_driver->vk_device, semaphore, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SEMAPHORE)); } - swap_chain->present_semaphores.clear(); + present_semaphores.clear(); +} + +#ifdef EXTERNAL_TARGET_ENABLED +void RenderingDeviceDriverVulkan::ExternalSwapChain::release() { + // Destroy views and framebuffers associated to the swapchain's images. + + { + MutexLock lock(mutex); + + images_released_callback.call(); + + if (!external_handle_transferred.is_empty()) { + for (uint32_t i = 0; i < images.size(); i++) { + if (!external_handle_transferred[i]) { + ERR_FAIL_COND(external_handles.is_empty()); +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__) + CloseHandle((HANDLE)external_handles[i]); +#elif defined(UNIX_ENABLED) + close(external_handles[i]); +#endif + } + } + external_handle_transferred.clear(); + } + if (!external_handles.is_empty()) { + external_handles.clear(); + } + if (!externally_acquired.is_empty()) { + for (uint32_t i = 0; i < images.size(); i++) { + if (externally_acquired[i]) { + ERR_FAIL_COND(image_memories.is_empty()); + ERR_FAIL_COND(images[i] == VK_NULL_HANDLE); + ERR_FAIL_COND(image_memories[i] == VK_NULL_HANDLE); + prev_acquired_images.insert(i, images[i]); + prev_acquired_memory.insert(i, image_memories[i]); + } + } + externally_acquired.clear(); + } + if (!allocation_sizes.is_empty()) { + allocation_sizes.clear(); + } + if (!memory_type_indices.is_empty()) { + memory_type_indices.clear(); + } + if (!image_create_infos.is_empty()) { + image_create_infos.clear(); + } + if (!in_use.is_empty()) { + in_use.clear(); + } + last_drawn_buffer = -1; + free_count = 0; + version += 1; + + if (!images.is_empty()) { + for (uint32_t i = 0; i < images.size(); i++) { + vkDestroyImageView(device_driver->vk_device, image_views[i], nullptr); + device_driver->framebuffer_free(framebuffers[i]); + if (!prev_acquired_images.has(i)) { + vkDestroyImage(device_driver->vk_device, images[i], nullptr); + } + if (image_memories[i] != VK_NULL_HANDLE && !prev_acquired_memory.has(i)) { + vkFreeMemory(device_driver->vk_device, image_memories[i], nullptr); + } + } + + image_index = UINT_MAX; + images.clear(); + image_views.clear(); + framebuffers.clear(); + image_memories.clear(); + } + + for (uint32_t i = 0; i < command_queues_acquired.size(); i++) { + device_driver->_recreate_image_semaphore(command_queues_acquired[i], command_queues_acquired_semaphores[i], false); + } + + command_queues_acquired.clear(); + command_queues_acquired_semaphores.clear(); + + for (VkSemaphore semaphore : present_semaphores) { + vkDestroySemaphore(device_driver->vk_device, semaphore, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SEMAPHORE)); + } + + present_semaphores.clear(); + } } +#endif RenderingDeviceDriver::SwapChainID RenderingDeviceDriverVulkan::swap_chain_create(RenderingContextDriver::SurfaceID p_surface) { DEV_ASSERT(p_surface != 0); @@ -3047,17 +3191,26 @@ RenderingDeviceDriver::SwapChainID RenderingDeviceDriverVulkan::swap_chain_creat // Retrieve the formats supported by the surface. uint32_t format_count = 0; - VkResult err = functions.GetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface->vk_surface, &format_count, nullptr); - ERR_FAIL_COND_V(err != VK_SUCCESS, SwapChainID()); + VkResult err = VK_SUCCESS; + if (surface->vk_surface) { + err = functions.GetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface->vk_surface, &format_count, nullptr); + } + ERR_FAIL_COND_V_MSG(err != VK_SUCCESS, SwapChainID(), string_VkResult(err)); TightLocalVector formats; formats.resize(format_count); - err = functions.GetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface->vk_surface, &format_count, formats.ptr()); - ERR_FAIL_COND_V(err != VK_SUCCESS, SwapChainID()); + if (surface->vk_surface) { + err = functions.GetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface->vk_surface, &format_count, formats.ptr()); + } + ERR_FAIL_COND_V_MSG(err != VK_SUCCESS, SwapChainID(), string_VkResult(err)); VkFormat format = VK_FORMAT_UNDEFINED; VkColorSpaceKHR color_space = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; - if (format_count == 1 && formats[0].format == VK_FORMAT_UNDEFINED) { + if (format_count == 0) { + // TODO let's use as default for now + format = VK_FORMAT_R8G8B8A8_UNORM; + color_space = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + } else if (format_count == 1 && formats[0].format == VK_FORMAT_UNDEFINED) { // If the format list includes just one entry of VK_FORMAT_UNDEFINED, the surface has no preferred format. format = VK_FORMAT_B8G8R8A8_UNORM; color_space = formats[0].colorSpace; @@ -3089,7 +3242,7 @@ RenderingDeviceDriver::SwapChainID RenderingDeviceDriverVulkan::swap_chain_creat attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + attachment.finalLayout = surface->headless ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; VkAttachmentReference2KHR color_reference = {}; color_reference.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR; @@ -3110,51 +3263,57 @@ RenderingDeviceDriver::SwapChainID RenderingDeviceDriverVulkan::swap_chain_creat VkRenderPass vk_render_pass = VK_NULL_HANDLE; err = _create_render_pass(vk_device, &pass_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_RENDER_PASS), &vk_render_pass); - ERR_FAIL_COND_V(err != VK_SUCCESS, SwapChainID()); + ERR_FAIL_COND_V_MSG(err != VK_SUCCESS, SwapChainID(), string_VkResult(err)); RenderPassInfo *render_pass_info = VersatileResource::allocate(resources_allocator); render_pass_info->vk_render_pass = vk_render_pass; - SwapChain *swap_chain = memnew(SwapChain); - swap_chain->surface = p_surface; - swap_chain->format = format; - swap_chain->color_space = color_space; - swap_chain->render_pass = RenderPassID(render_pass_info); + SwapChain *swap_chain = nullptr; + +#ifdef EXTERNAL_TARGET_ENABLED + if (surface->headless) { + swap_chain = memnew(ExternalSwapChain(this, p_surface, format, color_space, render_pass_info)); + } else +#endif + { + swap_chain = memnew(PresentableSwapChain(this, p_surface, format, color_space, render_pass_info)); + } + return SwapChainID(swap_chain); } -Error RenderingDeviceDriverVulkan::swap_chain_resize(CommandQueueID p_cmd_queue, SwapChainID p_swap_chain, uint32_t p_desired_framebuffer_count) { - DEV_ASSERT(p_cmd_queue.id != 0); - DEV_ASSERT(p_swap_chain.id != 0); +Error RenderingDeviceDriverVulkan::PresentableSwapChain::resize(CommandQueueID p_cmd_queue, uint32_t p_desired_framebuffer_count) { + // Release all current contents of the swap chain. + release(); - CommandQueue *command_queue = (CommandQueue *)(p_cmd_queue.id); - SwapChain *swap_chain = (SwapChain *)(p_swap_chain.id); + RenderingContextDriverVulkan::Surface *surface_ptr = (RenderingContextDriverVulkan::Surface *)(surface); - // Release all current contents of the swap chain. - _swap_chain_release(swap_chain); + uint32_t sp_image_count; + VkResult err = VK_SUCCESS; + + CommandQueue *command_queue = (CommandQueue *)(p_cmd_queue.id); // Validate if the command queue being used supports creating the swap chain for this surface. - const RenderingContextDriverVulkan::Functions &functions = context_driver->functions_get(); - if (!context_driver->queue_family_supports_present(physical_device, command_queue->queue_family, swap_chain->surface)) { + const RenderingContextDriverVulkan::Functions &functions = device_driver->context_driver->functions_get(); + if (!device_driver->context_driver->queue_family_supports_present(device_driver->physical_device, command_queue->queue_family, surface)) { ERR_FAIL_V_MSG(ERR_CANT_CREATE, "Surface is not supported by device. Did the GPU go offline? Was the window created on another monitor? Check" "previous errors & try launching with --gpu-validation."); } // Retrieve the surface's capabilities. - RenderingContextDriverVulkan::Surface *surface = (RenderingContextDriverVulkan::Surface *)(swap_chain->surface); VkSurfaceCapabilitiesKHR surface_capabilities = {}; - VkResult err = functions.GetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, surface->vk_surface, &surface_capabilities); - ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE); + err = functions.GetPhysicalDeviceSurfaceCapabilitiesKHR(device_driver->physical_device, surface_ptr->vk_surface, &surface_capabilities); + ERR_FAIL_COND_V_MSG(err != VK_SUCCESS, FAILED, string_VkResult(err)); // No swapchain yet, this is the first time we're creating it. - if (!swap_chain->vk_swapchain) { + if (!vk_swapchain) { if (surface_capabilities.currentExtent.width == 0xFFFFFFFF) { // The current extent is currently undefined, so the current surface width and height will be clamped to the surface's capabilities. // We make sure to overwrite surface_capabilities.currentExtent.width so that the same check further below // does not set extent.width = CLAMP( surface->width, ... ) on the first run of this function, because // that'd be potentially unswapped. - surface_capabilities.currentExtent.width = CLAMP(surface->width, surface_capabilities.minImageExtent.width, surface_capabilities.maxImageExtent.width); - surface_capabilities.currentExtent.height = CLAMP(surface->height, surface_capabilities.minImageExtent.height, surface_capabilities.maxImageExtent.height); + surface_capabilities.currentExtent.width = CLAMP(surface_ptr->width, surface_capabilities.minImageExtent.width, surface_capabilities.maxImageExtent.width); + surface_capabilities.currentExtent.height = CLAMP(surface_ptr->height, surface_capabilities.minImageExtent.height, surface_capabilities.maxImageExtent.height); } // We must SWAP() only once otherwise we'll keep ping-ponging between @@ -3169,17 +3328,16 @@ Error RenderingDeviceDriverVulkan::swap_chain_resize(CommandQueueID p_cmd_queue, VkExtent2D extent; if (surface_capabilities.currentExtent.width == 0xFFFFFFFF) { // The current extent is currently undefined, so the current surface width and height will be clamped to the surface's capabilities. - // We can only be here on the second call to swap_chain_resize(), by which time surface->width & surface->height should already be swapped if needed. - extent.width = CLAMP(surface->width, surface_capabilities.minImageExtent.width, surface_capabilities.maxImageExtent.width); - extent.height = CLAMP(surface->height, surface_capabilities.minImageExtent.height, surface_capabilities.maxImageExtent.height); + extent.width = CLAMP(surface_ptr->width, surface_capabilities.minImageExtent.width, surface_capabilities.maxImageExtent.width); + extent.height = CLAMP(surface_ptr->height, surface_capabilities.minImageExtent.height, surface_capabilities.maxImageExtent.height); } else { // Grab the dimensions from the current extent. extent = surface_capabilities.currentExtent; - surface->width = extent.width; - surface->height = extent.height; + surface_ptr->width = extent.width; + surface_ptr->height = extent.height; } - if (surface->width == 0 || surface->height == 0) { + if (surface_ptr->width == 0 || surface_ptr->height == 0) { // The surface doesn't have valid dimensions, so we can't create a swap chain. return ERR_SKIP; } @@ -3187,17 +3345,17 @@ Error RenderingDeviceDriverVulkan::swap_chain_resize(CommandQueueID p_cmd_queue, // Find what present modes are supported. TightLocalVector present_modes; uint32_t present_modes_count = 0; - err = functions.GetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface->vk_surface, &present_modes_count, nullptr); - ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE); + err = functions.GetPhysicalDeviceSurfacePresentModesKHR(device_driver->physical_device, surface_ptr->vk_surface, &present_modes_count, nullptr); + ERR_FAIL_COND_V_MSG(err != VK_SUCCESS, ERR_CANT_CREATE, string_VkResult(err)); present_modes.resize(present_modes_count); - err = functions.GetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface->vk_surface, &present_modes_count, present_modes.ptr()); - ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE); + err = functions.GetPhysicalDeviceSurfacePresentModesKHR(device_driver->physical_device, surface_ptr->vk_surface, &present_modes_count, present_modes.ptr()); + ERR_FAIL_COND_V_MSG(err != VK_SUCCESS, ERR_CANT_CREATE, string_VkResult(err)); // Choose the present mode based on the display server setting. VkPresentModeKHR present_mode = VkPresentModeKHR::VK_PRESENT_MODE_FIFO_KHR; String present_mode_name = "Enabled"; - switch (surface->vsync_mode) { + switch (surface_ptr->vsync_mode) { case DisplayServer::VSYNC_MAILBOX: present_mode = VK_PRESENT_MODE_MAILBOX_KHR; present_mode_name = "Mailbox"; @@ -3216,11 +3374,12 @@ Error RenderingDeviceDriverVulkan::swap_chain_resize(CommandQueueID p_cmd_queue, break; } + // Check if the requested mode is available. bool present_mode_available = present_modes.has(present_mode); if (!present_mode_available) { // Present mode is not available, fall back to FIFO which is guaranteed to be supported. WARN_PRINT(vformat("The requested V-Sync mode %s is not available. Falling back to V-Sync mode Enabled.", present_mode_name)); - surface->vsync_mode = DisplayServer::VSYNC_ENABLED; + surface_ptr->vsync_mode = DisplayServer::VSYNC_ENABLED; present_mode = VkPresentModeKHR::VK_PRESENT_MODE_FIFO_KHR; } @@ -3250,15 +3409,14 @@ Error RenderingDeviceDriverVulkan::swap_chain_resize(CommandQueueID p_cmd_queue, break; } } - has_comp_alpha[(uint64_t)p_cmd_queue.id] = (composite_alpha != VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR); } + device_driver->has_comp_alpha[(uint64_t)p_cmd_queue.id] = (composite_alpha != VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR); VkSwapchainCreateInfoKHR swap_create_info = {}; swap_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - swap_create_info.surface = surface->vk_surface; + swap_create_info.surface = surface_ptr->vk_surface; swap_create_info.minImageCount = desired_swapchain_images; - swap_create_info.imageFormat = swap_chain->format; - swap_create_info.imageColorSpace = swap_chain->color_space; + swap_create_info.imageFormat = format; swap_create_info.imageExtent = extent; swap_create_info.imageArrayLayers = 1; swap_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; @@ -3266,34 +3424,35 @@ Error RenderingDeviceDriverVulkan::swap_chain_resize(CommandQueueID p_cmd_queue, swap_create_info.preTransform = surface_transform_bits; switch (swap_create_info.preTransform) { case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR: - swap_chain->pre_transform_rotation_degrees = 0; + pre_transform_rotation_degrees = 0; break; case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR: - swap_chain->pre_transform_rotation_degrees = 90; + pre_transform_rotation_degrees = 90; break; case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR: - swap_chain->pre_transform_rotation_degrees = 180; + pre_transform_rotation_degrees = 180; break; case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR: - swap_chain->pre_transform_rotation_degrees = 270; + pre_transform_rotation_degrees = 270; break; default: WARN_PRINT("Unexpected swap_create_info.preTransform = " + itos(swap_create_info.preTransform) + "."); - swap_chain->pre_transform_rotation_degrees = 0; + pre_transform_rotation_degrees = 0; break; } swap_create_info.compositeAlpha = composite_alpha; swap_create_info.presentMode = present_mode; swap_create_info.clipped = true; - err = device_functions.CreateSwapchainKHR(vk_device, &swap_create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SWAPCHAIN_KHR), &swap_chain->vk_swapchain); - ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE); + + err = device_driver->device_functions.CreateSwapchainKHR(device_driver->vk_device, &swap_create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SWAPCHAIN_KHR), &vk_swapchain); + ERR_FAIL_COND_V_MSG(err != VK_SUCCESS, ERR_CANT_CREATE, string_VkResult(err)); #if defined(SWAPPY_FRAME_PACING_ENABLED) if (swappy_frame_pacer_enable) { SwappyVk_initAndGetRefreshCycleDuration(get_jni_env(), static_cast(OS::get_singleton())->get_godot_java()->get_activity(), physical_device, - vk_device, swap_chain->vk_swapchain, &swap_chain->refresh_duration); - SwappyVk_setWindow(vk_device, swap_chain->vk_swapchain, static_cast(OS::get_singleton())->get_native_window()); - SwappyVk_setSwapIntervalNS(vk_device, swap_chain->vk_swapchain, swap_chain->refresh_duration); + device_driver->vk_device, vk_swapchain, &refresh_duration); + SwappyVk_setWindow(device_driver->vk_device, vk_swapchain, static_cast(OS::get_singleton())->get_native_window()); + SwappyVk_setSwapIntervalNS(device_driver->vk_device, vk_swapchain, refresh_duration); enum SwappyModes { PIPELINE_FORCED_ON, @@ -3318,18 +3477,17 @@ Error RenderingDeviceDriverVulkan::swap_chain_resize(CommandQueueID p_cmd_queue, } #endif - uint32_t image_count = 0; - err = device_functions.GetSwapchainImagesKHR(vk_device, swap_chain->vk_swapchain, &image_count, nullptr); - ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE); + err = device_driver->device_functions.GetSwapchainImagesKHR(device_driver->vk_device, vk_swapchain, &sp_image_count, nullptr); + ERR_FAIL_COND_V_MSG(err != VK_SUCCESS, ERR_CANT_CREATE, string_VkResult(err)); - swap_chain->images.resize(image_count); - err = device_functions.GetSwapchainImagesKHR(vk_device, swap_chain->vk_swapchain, &image_count, swap_chain->images.ptr()); - ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE); + images.resize(sp_image_count); + err = device_driver->device_functions.GetSwapchainImagesKHR(device_driver->vk_device, vk_swapchain, &sp_image_count, images.ptr()); + ERR_FAIL_COND_V_MSG(err != VK_SUCCESS, ERR_CANT_CREATE, string_VkResult(err)); VkImageViewCreateInfo view_create_info = {}; view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; - view_create_info.format = swap_chain->format; + view_create_info.format = format; view_create_info.components.r = VK_COMPONENT_SWIZZLE_R; view_create_info.components.g = VK_COMPONENT_SWIZZLE_G; view_create_info.components.b = VK_COMPONENT_SWIZZLE_B; @@ -3338,65 +3496,265 @@ Error RenderingDeviceDriverVulkan::swap_chain_resize(CommandQueueID p_cmd_queue, view_create_info.subresourceRange.levelCount = 1; view_create_info.subresourceRange.layerCount = 1; - swap_chain->image_views.reserve(image_count); + image_views.reserve(sp_image_count); VkImageView image_view; - for (uint32_t i = 0; i < image_count; i++) { - view_create_info.image = swap_chain->images[i]; - err = vkCreateImageView(vk_device, &view_create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_IMAGE_VIEW), &image_view); - ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE); + for (uint32_t i = 0; i < sp_image_count; i++) { + view_create_info.image = images[i]; + err = vkCreateImageView(device_driver->vk_device, &view_create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_IMAGE_VIEW), &image_view); + ERR_FAIL_COND_V_MSG(err != VK_SUCCESS, ERR_CANT_CREATE, string_VkResult(err)); - swap_chain->image_views.push_back(image_view); + image_views.push_back(image_view); } - swap_chain->framebuffers.reserve(image_count); + framebuffers.reserve(sp_image_count); - const RenderPassInfo *render_pass = (const RenderPassInfo *)(swap_chain->render_pass.id); + const RenderPassInfo *render_pass_info = (const RenderPassInfo *)(render_pass.id); VkFramebufferCreateInfo fb_create_info = {}; fb_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - fb_create_info.renderPass = render_pass->vk_render_pass; + fb_create_info.renderPass = render_pass_info->vk_render_pass; fb_create_info.attachmentCount = 1; - fb_create_info.width = surface->width; - fb_create_info.height = surface->height; + fb_create_info.width = surface_ptr->width; + fb_create_info.height = surface_ptr->height; fb_create_info.layers = 1; VkFramebuffer vk_framebuffer; - for (uint32_t i = 0; i < image_count; i++) { - fb_create_info.pAttachments = &swap_chain->image_views[i]; - err = vkCreateFramebuffer(vk_device, &fb_create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_FRAMEBUFFER), &vk_framebuffer); - ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE); + for (uint32_t i = 0; i < sp_image_count; i++) { + fb_create_info.pAttachments = &image_views[i]; + err = vkCreateFramebuffer(device_driver->vk_device, &fb_create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_FRAMEBUFFER), &vk_framebuffer); + ERR_FAIL_COND_V_MSG(err != VK_SUCCESS, ERR_CANT_CREATE, string_VkResult(err)); Framebuffer *framebuffer = memnew(Framebuffer); framebuffer->vk_framebuffer = vk_framebuffer; - framebuffer->swap_chain_image = swap_chain->images[i]; + framebuffer->swap_chain_image = images[i]; framebuffer->swap_chain_image_subresource_range = view_create_info.subresourceRange; - swap_chain->framebuffers.push_back(RDD::FramebufferID(framebuffer)); + framebuffers.push_back(RDD::FramebufferID(framebuffer)); + } + + { + MutexLock lock(mutex); + in_use.resize(sp_image_count); + + for (uint32_t i = 0; i < sp_image_count; i++) { + in_use[i] = false; + } + + last_drawn_buffer = -1; } VkSemaphore vk_semaphore = VK_NULL_HANDLE; - for (uint32_t i = 0; i < image_count; i++) { + for (uint32_t i = 0; i < sp_image_count; i++) { VkSemaphoreCreateInfo create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - err = vkCreateSemaphore(vk_device, &create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SEMAPHORE), &vk_semaphore); + err = vkCreateSemaphore(device_driver->vk_device, &create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SEMAPHORE), &vk_semaphore); ERR_FAIL_COND_V(err != VK_SUCCESS, FAILED); - swap_chain->present_semaphores.push_back(vk_semaphore); + present_semaphores.push_back(vk_semaphore); } // Once everything's been created correctly, indicate the surface no longer needs to be resized. - context_driver->surface_set_needs_resize(swap_chain->surface, false); + device_driver->context_driver->surface_set_needs_resize(surface, false); return OK; } -RDD::FramebufferID RenderingDeviceDriverVulkan::swap_chain_acquire_framebuffer(CommandQueueID p_cmd_queue, SwapChainID p_swap_chain, bool &r_resize_required) { - DEV_ASSERT(p_cmd_queue); - DEV_ASSERT(p_swap_chain); +#ifdef EXTERNAL_TARGET_ENABLED +Error RenderingDeviceDriverVulkan::ExternalSwapChain::resize(CommandQueueID p_cmd_queue, uint32_t p_desired_framebuffer_count) { + // Release all current contents of the swap chain. + release(); + + RenderingContextDriverVulkan::Surface *surface_ptr = (RenderingContextDriverVulkan::Surface *)(surface); + + uint32_t sp_image_count = p_desired_framebuffer_count; + VkResult err = VK_SUCCESS; + + if (surface_ptr->width == 0 || surface_ptr->height == 0) { + // Likely window minimized, no swapchain created. + return ERR_SKIP; + } + + TightLocalVector swapchainImages; + swapchainImages.resize(sp_image_count); + TightLocalVector imageMemory; + imageMemory.resize(sp_image_count); + TightLocalVector externalHandles; + externalHandles.resize(sp_image_count); + TightLocalVector allocationSizes; + allocationSizes.resize(sp_image_count); + TightLocalVector memoryTypeIndices; + memoryTypeIndices.resize(sp_image_count); + TightLocalVector imageCreateInfos; + imageCreateInfos.resize(sp_image_count); + + { + MutexLock lock(mutex); + + for (uint32_t i = 0; i < swapchainImages.size(); i++) { + VkExternalMemoryImageCreateInfo externalMemoryImageCreateInfo = { + /*sType*/ VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO, + /*pNext*/ nullptr, +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__) + /*handleTypes*/ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT +#elif defined(UNIX_ENABLED) + /*handleTypes*/ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT +#endif + }; + + imageCreateInfos[i] = { + /*sType*/ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + /*pNext*/ &externalMemoryImageCreateInfo, + /*flags*/ 0, + /*imageType*/ VK_IMAGE_TYPE_2D, + /*format*/ format, + /*extent*/ { /*width*/ surface_ptr->width, + /*height*/ surface_ptr->height, + /*depth*/ 1 }, + /*mipLevels*/ 1, + /*arrayLayers*/ 1, + /*samples*/ VK_SAMPLE_COUNT_1_BIT, + /*tiling*/ VK_IMAGE_TILING_OPTIMAL, + /*usage*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, + /*sharingMode*/ VK_SHARING_MODE_EXCLUSIVE, + /*queueFamilyIndexCount*/ 0, + /*pQueueFamilyIndices*/ nullptr, + /*initialLayout*/ VK_IMAGE_LAYOUT_UNDEFINED + }; + err = vkCreateImage(device_driver->vk_device, &imageCreateInfos[i], nullptr, &swapchainImages[i]); + if (err) { + ERR_FAIL_V(ERR_CANT_CREATE); + } + + VkMemoryRequirements memory_requirements; + vkGetImageMemoryRequirements(device_driver->vk_device, swapchainImages[i], &memory_requirements); + + memoryTypeIndices[i] = 0; + for (uint32_t j = 0; j < device_driver->memory_properties.memoryTypeCount; j++) { + if (!(memory_requirements.memoryTypeBits & (1 << j))) { + continue; + } + memoryTypeIndices[i] = j; + } + + allocationSizes[i] = memory_requirements.size; + + VkExportMemoryAllocateInfo export_memory_allocate_info = { + VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, + nullptr, +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__) + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT +#elif defined(UNIX_ENABLED) + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT +#endif + }; + + VkMemoryAllocateInfo allocate_info = { + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + &export_memory_allocate_info, + allocationSizes[i], + memoryTypeIndices[i] + }; + + err = vkAllocateMemory(device_driver->vk_device, &allocate_info, nullptr, &imageMemory[i]); + ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE); + + err = vkBindImageMemory(device_driver->vk_device, swapchainImages[i], imageMemory[i], 0); + ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE); + + err = device_driver->get_external_memory_handle(device_driver->vk_device, imageMemory[i], &externalHandles[i]); + ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE); + } + + VkImageViewCreateInfo view_create_info = {}; + view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; + view_create_info.format = format; + view_create_info.components.r = VK_COMPONENT_SWIZZLE_R; + view_create_info.components.g = VK_COMPONENT_SWIZZLE_G; + view_create_info.components.b = VK_COMPONENT_SWIZZLE_B; + view_create_info.components.a = VK_COMPONENT_SWIZZLE_A; + view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + view_create_info.subresourceRange.levelCount = 1; + view_create_info.subresourceRange.layerCount = 1; + + image_views.reserve(sp_image_count); + + VkImageView image_view; + for (uint32_t i = 0; i < sp_image_count; i++) { + view_create_info.image = swapchainImages[i]; + err = vkCreateImageView(device_driver->vk_device, &view_create_info, nullptr, &image_view); + ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE); + + image_views.push_back(image_view); + image_memories.push_back(imageMemory[i]); + } + + framebuffers.reserve(sp_image_count); + + const RenderPassInfo *render_pass_info = (const RenderPassInfo *)(render_pass.id); + VkFramebufferCreateInfo fb_create_info = {}; + fb_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + fb_create_info.renderPass = render_pass_info->vk_render_pass; + fb_create_info.attachmentCount = 1; + fb_create_info.width = surface_ptr->width; + fb_create_info.height = surface_ptr->height; + fb_create_info.layers = 1; + + VkFramebuffer vk_framebuffer; + for (uint32_t i = 0; i < sp_image_count; i++) { + fb_create_info.pAttachments = &image_views[i]; + err = vkCreateFramebuffer(device_driver->vk_device, &fb_create_info, nullptr, &vk_framebuffer); + ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE); + + Framebuffer *framebuffer = memnew(Framebuffer); + framebuffer->vk_framebuffer = vk_framebuffer; + framebuffer->swap_chain_image = swapchainImages[i]; + framebuffer->swap_chain_image_subresource_range = view_create_info.subresourceRange; + framebuffers.push_back(RDD::FramebufferID(framebuffer)); + } + + images.resize(sp_image_count); + external_handles.resize(sp_image_count); + external_handle_transferred.resize(sp_image_count); + allocation_sizes.resize(sp_image_count); + memory_type_indices.resize(sp_image_count); + externally_acquired.resize(sp_image_count); + image_create_infos.resize(sp_image_count); + in_use.resize(sp_image_count); + for (uint32_t i = 0; i < sp_image_count; i++) { + images[i] = swapchainImages[i]; + external_handles[i] = externalHandles[i]; + external_handle_transferred[i] = false; + allocation_sizes[i] = allocationSizes[i]; + memory_type_indices[i] = memoryTypeIndices[i]; + image_create_infos[i] = imageCreateInfos[i]; + externally_acquired[i] = false; + in_use[i] = false; + } + free_count = sp_image_count; + last_drawn_buffer = -1; + + // Once everything's been created correctly, indicate the surface no longer needs to be resized. + device_driver->context_driver->surface_set_needs_resize(surface, false); + + images_created_callback.call(get_number_of_images_func, get_native_handle_func, get_allocation_size_func, get_memory_type_index_func, get_image_create_info_func); + } + + return OK; +} +#endif + +Error RenderingDeviceDriverVulkan::swap_chain_resize(CommandQueueID p_cmd_queue, SwapChainID p_swap_chain, uint32_t p_desired_framebuffer_count) { + DEV_ASSERT(p_cmd_queue.id != 0); + DEV_ASSERT(p_swap_chain.id != 0); - CommandQueue *command_queue = (CommandQueue *)(p_cmd_queue.id); SwapChain *swap_chain = (SwapChain *)(p_swap_chain.id); - if ((swap_chain->vk_swapchain == VK_NULL_HANDLE) || context_driver->surface_get_needs_resize(swap_chain->surface)) { + + return swap_chain->resize(p_cmd_queue, p_desired_framebuffer_count); +} + +RDD::FramebufferID RenderingDeviceDriverVulkan::PresentableSwapChain::acquire_framebuffer(CommandQueue *p_command_queue, bool &r_resize_required) { + if ((vk_swapchain == VK_NULL_HANDLE) || device_driver->context_driver->surface_get_needs_resize(surface)) { // The surface does not have a valid swap chain or it indicates it requires a resize. r_resize_required = true; return FramebufferID(); @@ -3405,33 +3763,33 @@ RDD::FramebufferID RenderingDeviceDriverVulkan::swap_chain_acquire_framebuffer(C VkResult err; VkSemaphore semaphore = VK_NULL_HANDLE; uint32_t semaphore_index = 0; - if (command_queue->free_image_semaphores.is_empty()) { + if (p_command_queue->free_image_semaphores.is_empty()) { // Add a new semaphore if none are free. VkSemaphoreCreateInfo create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - err = vkCreateSemaphore(vk_device, &create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SEMAPHORE), &semaphore); - ERR_FAIL_COND_V(err != VK_SUCCESS, FramebufferID()); + err = vkCreateSemaphore(device_driver->vk_device, &create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SEMAPHORE), &semaphore); + ERR_FAIL_COND_V_MSG(err != VK_SUCCESS, FramebufferID(), string_VkResult(err)); - semaphore_index = command_queue->image_semaphores.size(); - command_queue->image_semaphores.push_back(semaphore); - command_queue->image_semaphores_swap_chains.push_back(swap_chain); + semaphore_index = p_command_queue->image_semaphores.size(); + p_command_queue->image_semaphores.push_back(semaphore); + p_command_queue->image_semaphores_swap_chains.push_back(this); } else { // Pick a free semaphore. - uint32_t free_index = command_queue->free_image_semaphores.size() - 1; - semaphore_index = command_queue->free_image_semaphores[free_index]; - command_queue->image_semaphores_swap_chains[semaphore_index] = swap_chain; - command_queue->free_image_semaphores.remove_at(free_index); - semaphore = command_queue->image_semaphores[semaphore_index]; + uint32_t free_index = p_command_queue->free_image_semaphores.size() - 1; + semaphore_index = p_command_queue->free_image_semaphores[free_index]; + p_command_queue->image_semaphores_swap_chains[semaphore_index] = this; + p_command_queue->free_image_semaphores.remove_at(free_index); + semaphore = p_command_queue->image_semaphores[semaphore_index]; } // Store in the swap chain the acquired semaphore. - swap_chain->command_queues_acquired.push_back(command_queue); - swap_chain->command_queues_acquired_semaphores.push_back(semaphore_index); + command_queues_acquired.push_back(p_command_queue); + command_queues_acquired_semaphores.push_back(semaphore_index); - err = device_functions.AcquireNextImageKHR(vk_device, swap_chain->vk_swapchain, UINT64_MAX, semaphore, VK_NULL_HANDLE, &swap_chain->image_index); + err = device_driver->device_functions.AcquireNextImageKHR(device_driver->vk_device, vk_swapchain, UINT64_MAX, semaphore, VK_NULL_HANDLE, &image_index); if (err == VK_ERROR_OUT_OF_DATE_KHR) { // Out of date leaves the semaphore in a signaled state that will never finish, so it's necessary to recreate it. - bool semaphore_recreated = _recreate_image_semaphore(command_queue, semaphore_index, true); + bool semaphore_recreated = device_driver->_recreate_image_semaphore(p_command_queue, semaphore_index, true); ERR_FAIL_COND_V(!semaphore_recreated, FramebufferID()); // Swap chain is out of date and must be recreated. @@ -3445,35 +3803,77 @@ RDD::FramebufferID RenderingDeviceDriverVulkan::swap_chain_acquire_framebuffer(C // Indicate the command queue should wait on these semaphores on the next submission and that it should // indicate they're free again on the next fence. - command_queue->pending_semaphores_for_execute.push_back(semaphore_index); - command_queue->pending_semaphores_for_fence.push_back(semaphore_index); + p_command_queue->pending_semaphores_for_execute.push_back(semaphore_index); + p_command_queue->pending_semaphores_for_fence.push_back(semaphore_index); + + { + MutexLock external_lock(mutex); + in_use[image_index] = true; + } // Return the corresponding framebuffer to the new current image. - FramebufferID framebuffer_id = swap_chain->framebuffers[swap_chain->image_index]; + FramebufferID framebuffer_id = framebuffers[image_index]; Framebuffer *framebuffer = (Framebuffer *)(framebuffer_id.id); framebuffer->swap_chain_acquired = true; return framebuffer_id; } +#ifdef EXTERNAL_TARGET_ENABLED +RDD::FramebufferID RenderingDeviceDriverVulkan::ExternalSwapChain::acquire_framebuffer(CommandQueue *p_command_queue, bool &r_resize_required) { + // NOTE: + // external_swapchain_acquire_next is NOT acquire_framebuffer + // acquire_framebuffer happens internally and it acquires a free image for drawing. + // External acquiring means the host acquires an already rendered image for displaying. -> ExternalSwapChain::grab_image -> Only RenderingNativeSurfaceExternalTarget will call this. + + MutexLock external_lock(mutex); + + if (images.is_empty() || device_driver->context_driver->surface_get_needs_resize(surface)) { + r_resize_required = true; + return FramebufferID(); + } + + ERR_FAIL_COND_V_MSG(free_count == 0, FramebufferID(), "All images of the swapchain have been externally acquired."); + uint32_t count = 0; + do { + ERR_FAIL_COND_V_MSG(count == images.size(), FramebufferID(), "All images of the swapchain has been externally acquired."); + count++; + image_index = (image_index + 1) % images.size(); + } while (externally_acquired[image_index] || image_index == last_drawn_buffer); + in_use[image_index] = true; + + return framebuffers[image_index]; +} +#endif + +RDD::FramebufferID RenderingDeviceDriverVulkan::swap_chain_acquire_framebuffer(CommandQueueID p_cmd_queue, SwapChainID p_swap_chain, bool &r_resize_required) { + DEV_ASSERT(p_cmd_queue); + DEV_ASSERT(p_swap_chain); + + CommandQueue *command_queue = (CommandQueue *)(p_cmd_queue.id); + SwapChain *swap_chain = (SwapChain *)(p_swap_chain.id); + + return swap_chain->acquire_framebuffer(command_queue, r_resize_required); +} + RDD::RenderPassID RenderingDeviceDriverVulkan::swap_chain_get_render_pass(SwapChainID p_swap_chain) { DEV_ASSERT(p_swap_chain.id != 0); SwapChain *swap_chain = (SwapChain *)(p_swap_chain.id); - return swap_chain->render_pass; + return swap_chain->get_render_pass(); } int RenderingDeviceDriverVulkan::swap_chain_get_pre_rotation_degrees(SwapChainID p_swap_chain) { DEV_ASSERT(p_swap_chain.id != 0); SwapChain *swap_chain = (SwapChain *)(p_swap_chain.id); - return swap_chain->pre_transform_rotation_degrees; + return swap_chain->get_pre_transform_rotation_degrees(); } RDD::DataFormat RenderingDeviceDriverVulkan::swap_chain_get_format(SwapChainID p_swap_chain) { DEV_ASSERT(p_swap_chain.id != 0); SwapChain *swap_chain = (SwapChain *)(p_swap_chain.id); - switch (swap_chain->format) { + switch (swap_chain->get_format()) { case VK_FORMAT_B8G8R8A8_UNORM: return DATA_FORMAT_B8G8R8A8_UNORM; case VK_FORMAT_R8G8B8A8_UNORM: @@ -3500,19 +3900,105 @@ void RenderingDeviceDriverVulkan::swap_chain_set_max_fps(SwapChainID p_swap_chai #endif } +#ifdef EXTERNAL_TARGET_ENABLED +BinaryMutex *RenderingDeviceDriverVulkan::swap_chain_get_mutex(SwapChainID p_swap_chain) { + SwapChain *swap_chain = (SwapChain *)(p_swap_chain.id); + + return &swap_chain->get_mutex(); +} + +void RenderingDeviceDriverVulkan::swap_chain_set_frame_in_use(SwapChainID p_swap_chain, size_t p_index, bool p_in_use) { + SwapChain *swap_chain = (SwapChain *)(p_swap_chain.id); + + swap_chain->set_frame_in_use(p_index, p_in_use); +} + +int RenderingDeviceDriverVulkan::swap_chain_get_last_drawn_buffer(SwapChainID p_swap_chain) { + SwapChain *swap_chain = (SwapChain *)(p_swap_chain.id); + + return swap_chain->get_last_drawn_buffer(); +} + +void RenderingDeviceDriverVulkan::swap_chain_set_last_drawn_buffer(SwapChainID p_swap_chain, int p_buffer) { + SwapChain *swap_chain = (SwapChain *)(p_swap_chain.id); + + swap_chain->set_last_drawn_buffer(p_buffer); +} + +uint32_t RenderingDeviceDriverVulkan::swap_chain_get_image_index(SwapChainID p_swap_chain) { + SwapChain *swap_chain = (SwapChain *)(p_swap_chain.id); + + return swap_chain->get_image_index(); +} + +uint64_t RenderingDeviceDriverVulkan::swap_chain_get_version(SwapChainID p_swap_chain) { + SwapChain *swap_chain = (SwapChain *)(p_swap_chain.id); + + return swap_chain->get_version(); +} +#endif + void RenderingDeviceDriverVulkan::swap_chain_free(SwapChainID p_swap_chain) { DEV_ASSERT(p_swap_chain.id != 0); SwapChain *swap_chain = (SwapChain *)(p_swap_chain.id); - _swap_chain_release(swap_chain); + swap_chain->release(); - if (swap_chain->render_pass) { - render_pass_free(swap_chain->render_pass); + if (swap_chain->get_render_pass()) { + render_pass_free(swap_chain->get_render_pass()); } memdelete(swap_chain); } +#ifdef EXTERNAL_TARGET_ENABLED +void RenderingDeviceDriverVulkan::external_swap_chain_set_callbacks(SwapChainID p_swap_chain, Callable p_images_created, Callable p_images_released) { + ExternalSwapChain *swap_chain = (ExternalSwapChain *)(p_swap_chain.id); + + swap_chain->set_callbacks(p_images_created, p_images_released); +} + +void RenderingDeviceDriverVulkan::external_swap_chain_release_image(SwapChainID p_swap_chain, uint32_t p_index) { + ExternalSwapChain *swap_chain = (ExternalSwapChain *)(p_swap_chain.id); + + swap_chain->release_image(p_index); +} + +VkImage RenderingDeviceDriverVulkan::external_swap_chain_get_image(SwapChainID p_swap_chain, uint32_t p_index) { + ExternalSwapChain *swap_chain = (ExternalSwapChain *)(p_swap_chain.id); + + return swap_chain->get_image(p_index); +} + +int RenderingDeviceDriverVulkan::external_swap_chain_grab_image(SwapChainID p_swap_chain) { + ExternalSwapChain *swap_chain = (ExternalSwapChain *)(p_swap_chain.id); + + return swap_chain->grab_image(); +} + +VkResult RenderingDeviceDriverVulkan::get_external_memory_handle(VkDevice p_device, VkDeviceMemory p_device_memory, uint64_t *p_external_handle_out) { +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__) + VkMemoryGetWin32HandleInfoKHR memory_get_win32_info = { + VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR, + nullptr, + p_device_memory, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT + }; + return vkGetMemoryWin32HandleKHR(p_device, &memory_get_win32_info, (HANDLE *)p_external_handle_out); +#elif defined(UNIX_ENABLED) + VkMemoryGetFdInfoKHR memory_get_fd_info = { + VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR, + nullptr, + p_device_memory, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT + }; + return device_functions.GetMemoryFdKHR(p_device, &memory_get_fd_info, (int *)p_external_handle_out); +#else + return VK_ERROR_INITIALIZATION_FAILED; +#endif +} +#endif + /*********************/ /**** FRAMEBUFFER ****/ /*********************/ @@ -4129,7 +4615,6 @@ RDD::UniformSetID RenderingDeviceDriverVulkan::uniform_set_create(VectorViewvk_descriptor_set_layouts[p_set_index]; VkDescriptorSet vk_descriptor_set = VK_NULL_HANDLE; - VkResult res = vkAllocateDescriptorSets(vk_device, &descriptor_set_allocate_info, &vk_descriptor_set); if (res) { _descriptor_set_pool_unreference(pool_sets_it, vk_pool, p_linear_pool_index); @@ -4470,7 +4955,7 @@ Vector RenderingDeviceDriverVulkan::pipeline_cache_serialize() { pipelines_cache.buffer.resize(pipelines_cache.current_size + sizeof(PipelineCacheHeader)); VkResult err = vkGetPipelineCacheData(vk_device, pipelines_cache.vk_cache, &pipelines_cache.current_size, pipelines_cache.buffer.ptrw() + sizeof(PipelineCacheHeader)); - ERR_FAIL_COND_V(err != VK_SUCCESS && err != VK_INCOMPLETE, Vector()); // Incomplete is OK because the cache may have grown since the size was queried (unless when exiting). + ERR_FAIL_COND_V_MSG(err != VK_SUCCESS && err != VK_INCOMPLETE, Vector(), string_VkResult(err)); // Incomplete is OK because the cache may have grown since the size was queried (unless when exiting). // The real buffer size may now be bigger than the updated current_size. // We take into account the new size but keep the buffer resized in a worst-case fashion. diff --git a/drivers/vulkan/rendering_device_driver_vulkan.h b/drivers/vulkan/rendering_device_driver_vulkan.h index 873eb446a170..542db0e8b80d 100644 --- a/drivers/vulkan/rendering_device_driver_vulkan.h +++ b/drivers/vulkan/rendering_device_driver_vulkan.h @@ -45,6 +45,8 @@ #include "drivers/vulkan/godot_vulkan.h" +#undef MemoryBarrier + // Design principles: // - Vulkan structs are zero-initialized and fields not requiring a non-zero value are omitted (except in cases where expresivity reasons apply). class RenderingDeviceDriverVulkan : public RenderingDeviceDriver { @@ -53,7 +55,7 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver { /*****************/ struct CommandQueue; - struct SwapChain; + class SwapChain; struct CommandBufferInfo; struct RenderPassInfo; struct Framebuffer; @@ -108,6 +110,8 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver { // Debug device fault. PFN_vkGetDeviceFaultInfoEXT GetDeviceFaultInfoEXT = nullptr; + + PFN_vkGetMemoryFdKHR GetMemoryFdKHR = nullptr; }; // Debug marker extensions. VkDebugReportObjectTypeEXT _convert_to_debug_report_objectType(VkObjectType p_object_type); @@ -146,6 +150,7 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver { uint8_t swappy_mode = 2; // See default value for display/window/frame_pacing/android/swappy_mode. #endif DeviceFunctions device_functions; + VkPhysicalDeviceMemoryProperties memory_properties; void _register_requested_device_extension(const CharString &p_extension_name, bool p_required); Error _initialize_device_extensions(); @@ -153,6 +158,7 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver { Error _check_device_capabilities(); void _choose_vrs_capabilities(); Error _add_queue_create_info(LocalVector &r_queue_create_info); + Error _init_device_functions(VkDevice device); Error _initialize_device(const LocalVector &p_queue_create_info); Error _initialize_allocator(); Error _initialize_pipeline_cache(); @@ -286,6 +292,7 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver { public: virtual FenceID fence_create() override final; virtual Error fence_wait(FenceID p_fence) override final; + virtual void frame_cleanup(FenceID p_fence) override final; virtual void fence_free(FenceID p_fence) override final; /********************/ @@ -356,11 +363,11 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver { /********************/ private: - struct SwapChain { - VkSwapchainKHR vk_swapchain = VK_NULL_HANDLE; + class SwapChain { + protected: + RenderingDeviceDriverVulkan *device_driver; RenderingContextDriver::SurfaceID surface = RenderingContextDriver::SurfaceID(); VkFormat format = VK_FORMAT_UNDEFINED; - VkColorSpaceKHR color_space = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; TightLocalVector images; TightLocalVector image_views; TightLocalVector present_semaphores; @@ -373,7 +380,517 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver { #ifdef ANDROID_ENABLED uint64_t refresh_duration = 0; #endif + VkColorSpaceKHR color_space = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + BinaryMutex mutex; + TightLocalVector in_use; + int last_drawn_buffer = 0; + uint64_t version = 0; + + public: + virtual VkSwapchainKHR get_swapchain_handle() const { return VK_NULL_HANDLE; } + + RenderingContextDriver::SurfaceID get_surface() const { return surface; } + + VkFormat get_format() const { return format; } + + uint32_t get_number_of_images() const { return images.size(); } + + VkImage get_image(uint32_t p_index) const { return images[p_index]; } + + VkSemaphore get_present_semaphore(uint32_t p_index) const { return present_semaphores[p_index]; } + + RenderPassID get_render_pass() const { return render_pass; } + + int get_pre_transform_rotation_degrees() const { return pre_transform_rotation_degrees; } + + uint32_t get_image_index() const { return image_index; } + + void set_image_index(uint32_t p_image_index) { + ERR_FAIL_COND(p_image_index < 0); + image_index = p_image_index; + } + + BinaryMutex &get_mutex() { + return mutex; + } + + void set_frame_in_use(size_t p_index, bool p_in_use) { + if (images.size() == 0) { + return; + } + + in_use[p_index] = p_in_use; + } + + int get_last_drawn_buffer() { + return last_drawn_buffer; + } + + void set_last_drawn_buffer(int p_last_drawn_buffer) { + last_drawn_buffer = p_last_drawn_buffer; + } + + uint64_t get_version() const { return version; } + + void set_color_space(VkColorSpaceKHR p_color_space) { color_space = p_color_space; } + + virtual FramebufferID acquire_framebuffer(CommandQueue *p_command_queue, bool &r_resize_required) = 0; + + virtual bool release_image_semaphore(CommandQueue *p_command_queue, uint32_t p_semaphore_index); + + virtual Error resize(CommandQueueID p_cmd_queue, uint32_t p_desired_framebuffer_count) = 0; + + virtual void release() = 0; + + SwapChain(RenderingDeviceDriverVulkan *p_device_driver, RenderingContextDriver::SurfaceID p_surface, VkFormat p_format, VkColorSpaceKHR p_color_space, RenderPassInfo *p_render_pass) { + this->device_driver = p_device_driver; + this->surface = p_surface; + this->format = p_format; + this->color_space = p_color_space; + this->render_pass = RenderPassID(p_render_pass); + } + + virtual ~SwapChain() = default; + }; + + class PresentableSwapChain : public SwapChain { + VkSwapchainKHR vk_swapchain = VK_NULL_HANDLE; + + public: + virtual VkSwapchainKHR get_swapchain_handle() const override { return vk_swapchain; } + + virtual FramebufferID acquire_framebuffer(CommandQueue *p_command_queue, bool &r_resize_required) override final; + + virtual Error resize(CommandQueueID p_cmd_queue, uint32_t p_desired_framebuffer_count) override final; + + virtual void release() override final; + + PresentableSwapChain( + RenderingDeviceDriverVulkan *p_device_driver, + RenderingContextDriver::SurfaceID p_surface, + VkFormat p_format, + VkColorSpaceKHR p_color_space, + RenderPassInfo *p_render_pass) : + SwapChain(p_device_driver, p_surface, p_format, p_color_space, p_render_pass) {} + }; + +#ifdef EXTERNAL_TARGET_ENABLED + class ExternalSwapChain : public SwapChain { + TightLocalVector image_memories; + TightLocalVector externally_acquired; + TightLocalVector external_handles; + TightLocalVector external_handle_transferred; + TightLocalVector allocation_sizes; + TightLocalVector memory_type_indices; + TightLocalVector image_create_infos; + uint32_t free_count = 0; + HashMap prev_acquired_images; + HashMap prev_acquired_memory; + + Callable images_created_callback; + Callable get_number_of_images_func; + Callable get_native_handle_func; + Callable get_allocation_size_func; + Callable get_memory_type_index_func; + Callable get_image_create_info_func; + + Callable images_released_callback; + + public: + void set_callbacks(Callable p_images_created, Callable p_images_released) { + images_created_callback = p_images_created; + images_released_callback = p_images_released; + } + + uint64_t get_native_handle(int p_index) { + // This should only be called once for each id, after the external swapchain has been created. + // Calling this function transfers ownership of the native handle to the caller. + external_handle_transferred[p_index] = true; + return external_handles[p_index]; + } + + uint64_t get_allocation_size(int p_index) { + return allocation_sizes[p_index]; + } + + uint32_t get_memory_type_index(int p_index) { + return memory_type_indices[p_index]; + } + + uint64_t get_image_create_info(int p_index) { + return (uint64_t)&image_create_infos[p_index]; + } + + void release_image(int p_index) { + MutexLock lock(mutex); + ERR_FAIL_COND(!externally_acquired[p_index]); + ERR_FAIL_COND(in_use[p_index]); + externally_acquired[p_index] = false; + free_count += 1; + } + + virtual FramebufferID acquire_framebuffer(CommandQueue *p_command_queue, bool &r_resize_required) override final; + + int grab_image() { + MutexLock lock(mutex); + int acquired_buffer = last_drawn_buffer; + if (acquired_buffer == -1) { + return -1; + } + if (in_use[acquired_buffer]) { + return -1; + } + if (free_count == 1) { + return -1; + } + if (externally_acquired[acquired_buffer]) { + return -1; + } + last_drawn_buffer = -1; + externally_acquired[acquired_buffer] = true; + free_count -= 1; + if (!prev_acquired_images.is_empty() || !prev_acquired_memory.is_empty()) { + for (KeyValue &E : prev_acquired_images) { + const VkImage &image = E.value; + vkDestroyImage(device_driver->vk_device, image, nullptr); + } + for (KeyValue &E : prev_acquired_memory) { + const VkDeviceMemory &memory = E.value; + vkFreeMemory(device_driver->vk_device, memory, nullptr); + } + prev_acquired_images.clear(); + prev_acquired_memory.clear(); + } + return acquired_buffer; + } + + virtual Error resize(CommandQueueID p_cmd_queue, uint32_t p_desired_framebuffer_count) override final; + + virtual void release() override final; + + ExternalSwapChain( + RenderingDeviceDriverVulkan *p_device_driver, + RenderingContextDriver::SurfaceID p_surface, + VkFormat p_format, + VkColorSpaceKHR p_color_space, + RenderPassInfo *p_render_pass) : + SwapChain(p_device_driver, p_surface, p_format, p_color_space, p_render_pass) { + get_number_of_images_func = Callable(new ExternalSwapChainGetNumberOfImages(this)); + get_native_handle_func = Callable(new ExternalSwapChainGetNativeHandle(this)); + get_allocation_size_func = Callable(new ExternalSwapChainGetAllocationSize(this)); + get_memory_type_index_func = Callable(new ExternalSwapChainGetMemoryTypeIndex(this)); + get_image_create_info_func = Callable(new ExternalSwapChainGetImageCreateInfo(this)); + } + }; + + class ExternalSwapChainGetNumberOfImages : public CallableCustom { + ExternalSwapChain *swapchain = nullptr; + + public: + virtual uint32_t hash() const override { + return (intptr_t)this; + } + + virtual String get_as_text() const override { + return ""; + } + + static bool compare_equal_func(const CallableCustom *p_a, const CallableCustom *p_b) { + return p_a == p_b; + } + + virtual CallableCustom::CompareEqualFunc get_compare_equal_func() const override { + return &ExternalSwapChainGetNumberOfImages::compare_equal_func; + } + + static bool compare_less_func(const CallableCustom *p_a, const CallableCustom *p_b) { + return (void *)p_a < (void *)p_b; + } + + virtual CallableCustom::CompareLessFunc get_compare_less_func() const override { + return &ExternalSwapChainGetNumberOfImages::compare_less_func; + } + + bool is_valid() const override { + return true; + } + + virtual ObjectID get_object() const override { + return ObjectID(); + } + + virtual int get_argument_count(bool &r_is_valid) const override { + r_is_valid = true; + return 0; + } + + virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override { + r_return_value = Variant(swapchain->get_number_of_images()); + r_call_error.error = Callable::CallError::CALL_OK; + } + + ExternalSwapChainGetNumberOfImages(ExternalSwapChain *p_swapchain) : + CallableCustom() { + swapchain = p_swapchain; + } + }; + + class ExternalSwapChainGetNativeHandle : public CallableCustom { + ExternalSwapChain *swapchain = nullptr; + const int required_argument_count = 1; + + public: + virtual uint32_t hash() const override { + return (intptr_t)this; + } + + virtual String get_as_text() const override { + return ""; + } + + static bool compare_equal_func(const CallableCustom *p_a, const CallableCustom *p_b) { + return p_a == p_b; + } + + virtual CallableCustom::CompareEqualFunc get_compare_equal_func() const override { + return &ExternalSwapChainGetNativeHandle::compare_equal_func; + } + + static bool compare_less_func(const CallableCustom *p_a, const CallableCustom *p_b) { + return (void *)p_a < (void *)p_b; + } + + virtual CallableCustom::CompareLessFunc get_compare_less_func() const override { + return &ExternalSwapChainGetNativeHandle::compare_less_func; + } + + bool is_valid() const override { + return true; + } + + virtual ObjectID get_object() const override { + return ObjectID(); + } + + virtual int get_argument_count(bool &r_is_valid) const override { + r_is_valid = true; + return required_argument_count; + } + + virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override { + if (p_argcount == 0) { + ERR_PRINT("ExternalSwapChainGetNativeHandle requires " + itos(required_argument_count) + " argument but none were given."); + r_return_value = -1; + r_call_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + } else if (p_argcount > required_argument_count) { + ERR_PRINT("ExternalSwapChainGetNativeHandle requires " + itos(required_argument_count) + " argument but " + itos(p_argcount) + " were given."); + r_return_value = -1; + r_call_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; + } + + uint64_t p_index = (uint64_t)*p_arguments[0]; + r_return_value = Variant(swapchain->get_native_handle(p_index)); + r_call_error.error = Callable::CallError::CALL_OK; + } + + ExternalSwapChainGetNativeHandle(ExternalSwapChain *p_swapchain) : + CallableCustom() { + swapchain = p_swapchain; + } + }; + + class ExternalSwapChainGetAllocationSize : public CallableCustom { + ExternalSwapChain *swapchain = nullptr; + const int required_argument_count = 1; + + public: + virtual uint32_t hash() const override { + return (intptr_t)this; + } + + virtual String get_as_text() const override { + return ""; + } + + static bool compare_equal_func(const CallableCustom *p_a, const CallableCustom *p_b) { + return p_a == p_b; + } + + virtual CallableCustom::CompareEqualFunc get_compare_equal_func() const override { + return &ExternalSwapChainGetAllocationSize::compare_equal_func; + } + + static bool compare_less_func(const CallableCustom *p_a, const CallableCustom *p_b) { + return (void *)p_a < (void *)p_b; + } + + virtual CallableCustom::CompareLessFunc get_compare_less_func() const override { + return &ExternalSwapChainGetAllocationSize::compare_less_func; + } + + bool is_valid() const override { + return true; + } + + virtual ObjectID get_object() const override { + return ObjectID(); + } + + virtual int get_argument_count(bool &r_is_valid) const override { + r_is_valid = true; + return required_argument_count; + } + + virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override { + if (p_argcount == 0) { + ERR_PRINT("ExternalSwapChainGetAllocationSize requires " + itos(required_argument_count) + " argument but none were given."); + r_return_value = -1; + r_call_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + } else if (p_argcount > required_argument_count) { + ERR_PRINT("ExternalSwapChainGetAllocationSize requires " + itos(required_argument_count) + " argument but " + itos(p_argcount) + " were given."); + r_return_value = -1; + r_call_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; + } + + uint64_t p_index = (uint64_t)*p_arguments[0]; + r_return_value = Variant(swapchain->get_allocation_size(p_index)); + r_call_error.error = Callable::CallError::CALL_OK; + } + + ExternalSwapChainGetAllocationSize(ExternalSwapChain *p_swapchain) : + CallableCustom() { + swapchain = p_swapchain; + } + }; + + class ExternalSwapChainGetMemoryTypeIndex : public CallableCustom { + ExternalSwapChain *swapchain = nullptr; + const int required_argument_count = 1; + + public: + virtual uint32_t hash() const override { + return (intptr_t)this; + } + + virtual String get_as_text() const override { + return ""; + } + + static bool compare_equal_func(const CallableCustom *p_a, const CallableCustom *p_b) { + return p_a == p_b; + } + + virtual CallableCustom::CompareEqualFunc get_compare_equal_func() const override { + return &ExternalSwapChainGetMemoryTypeIndex::compare_equal_func; + } + + static bool compare_less_func(const CallableCustom *p_a, const CallableCustom *p_b) { + return (void *)p_a < (void *)p_b; + } + + virtual CallableCustom::CompareLessFunc get_compare_less_func() const override { + return &ExternalSwapChainGetMemoryTypeIndex::compare_less_func; + } + + bool is_valid() const override { + return true; + } + + virtual ObjectID get_object() const override { + return ObjectID(); + } + + virtual int get_argument_count(bool &r_is_valid) const override { + r_is_valid = true; + return required_argument_count; + } + + virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override { + if (p_argcount == 0) { + ERR_PRINT("ExternalSwapChainGetMemoryTypeIndex requires " + itos(required_argument_count) + " argument but none were given."); + r_return_value = -1; + r_call_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + } else if (p_argcount > required_argument_count) { + ERR_PRINT("ExternalSwapChainGetMemoryTypeIndex requires " + itos(required_argument_count) + " argument but " + itos(p_argcount) + " were given."); + r_return_value = -1; + r_call_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; + } + + uint64_t p_index = (uint64_t)*p_arguments[0]; + r_return_value = Variant(swapchain->get_memory_type_index(p_index)); + r_call_error.error = Callable::CallError::CALL_OK; + } + + ExternalSwapChainGetMemoryTypeIndex(ExternalSwapChain *p_swapchain) : + CallableCustom() { + swapchain = p_swapchain; + } + }; + + class ExternalSwapChainGetImageCreateInfo : public CallableCustom { + ExternalSwapChain *swapchain = nullptr; + const int required_argument_count = 1; + + public: + virtual uint32_t hash() const override { + return (intptr_t)this; + } + + virtual String get_as_text() const override { + return ""; + } + + static bool compare_equal_func(const CallableCustom *p_a, const CallableCustom *p_b) { + return p_a == p_b; + } + + virtual CallableCustom::CompareEqualFunc get_compare_equal_func() const override { + return &ExternalSwapChainGetImageCreateInfo::compare_equal_func; + } + + static bool compare_less_func(const CallableCustom *p_a, const CallableCustom *p_b) { + return (void *)p_a < (void *)p_b; + } + + virtual CallableCustom::CompareLessFunc get_compare_less_func() const override { + return &ExternalSwapChainGetImageCreateInfo::compare_less_func; + } + + bool is_valid() const override { + return true; + } + + virtual ObjectID get_object() const override { + return ObjectID(); + } + + virtual int get_argument_count(bool &r_is_valid) const override { + r_is_valid = true; + return required_argument_count; + } + + virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override { + if (p_argcount == 0) { + ERR_PRINT("ExternalSwapChainGetImageCreateInfo requires " + itos(required_argument_count) + " argument but none were given."); + r_return_value = -1; + r_call_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + } else if (p_argcount > required_argument_count) { + ERR_PRINT("ExternalSwapChainGetImageCreateInfo requires " + itos(required_argument_count) + " argument but " + itos(p_argcount) + " were given."); + r_return_value = -1; + r_call_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; + } + + uint64_t p_index = (uint64_t)*p_arguments[0]; + r_return_value = Variant(swapchain->get_image_create_info(p_index)); + r_call_error.error = Callable::CallError::CALL_OK; + } + + ExternalSwapChainGetImageCreateInfo(ExternalSwapChain *p_swapchain) : + CallableCustom() { + swapchain = p_swapchain; + } }; +#endif void _swap_chain_release(SwapChain *p_swap_chain); @@ -385,8 +902,25 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver { virtual int swap_chain_get_pre_rotation_degrees(SwapChainID p_swap_chain) override final; virtual DataFormat swap_chain_get_format(SwapChainID p_swap_chain) override final; virtual void swap_chain_set_max_fps(SwapChainID p_swap_chain, int p_max_fps) override final; +#ifdef EXTERNAL_TARGET_ENABLED + virtual BinaryMutex *swap_chain_get_mutex(SwapChainID p_swap_chain) override final; + virtual void swap_chain_set_frame_in_use(SwapChainID p_swap_chain, size_t p_index, bool p_in_use) override final; + virtual int swap_chain_get_last_drawn_buffer(SwapChainID p_swap_chain) override final; + virtual void swap_chain_set_last_drawn_buffer(SwapChainID p_swap_chain, int p_buffer) override final; + virtual uint32_t swap_chain_get_image_index(SwapChainID p_swap_chain) override final; + virtual uint64_t swap_chain_get_version(SwapChainID p_swap_chain) override final; +#endif virtual void swap_chain_free(SwapChainID p_swap_chain) override final; +#ifdef EXTERNAL_TARGET_ENABLED + void external_swap_chain_set_callbacks(SwapChainID p_swap_chain, Callable p_images_created, Callable p_images_released); + void external_swap_chain_release_image(SwapChainID p_swap_chain, uint32_t p_index); + VkImage external_swap_chain_get_image(SwapChainID p_swap_chain, uint32_t p_index); + int external_swap_chain_grab_image(SwapChainID p_swap_chain); + + VkResult get_external_memory_handle(VkDevice p_device, VkDeviceMemory p_device_memory, uint64_t *p_exernal_handle_out); +#endif + private: /*********************/ /**** FRAMEBUFFER ****/ diff --git a/drivers/vulkan/rendering_native_surface_vulkan.cpp b/drivers/vulkan/rendering_native_surface_vulkan.cpp new file mode 100644 index 000000000000..7cde710653e4 --- /dev/null +++ b/drivers/vulkan/rendering_native_surface_vulkan.cpp @@ -0,0 +1,80 @@ +/**************************************************************************/ +/* rendering_native_surface_vulkan.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_native_surface_vulkan.h" + +#include "drivers/vulkan/rendering_context_driver_vulkan.h" + +void RenderingNativeSurfaceVulkan::_bind_methods() { + ClassDB::bind_static_method("RenderingNativeSurfaceVulkan", D_METHOD("create", "vulkan_surface"), &RenderingNativeSurfaceVulkan::create_api); +} + +Ref RenderingNativeSurfaceVulkan::create_api(GDExtensionConstPtr p_vulkan_surface) { + Ref result = nullptr; +#ifdef VULKAN_ENABLED + result = RenderingNativeSurfaceVulkan::create((VkSurfaceKHR)p_vulkan_surface.operator const void *()); +#endif + return result; +} + +#ifdef VULKAN_ENABLED + +Ref RenderingNativeSurfaceVulkan::create(VkSurfaceKHR p_vulkan_surface) { + Ref result = memnew(RenderingNativeSurfaceVulkan); + result->vulkan_surface = p_vulkan_surface; + return result; +} + +#endif + +void *RenderingNativeSurfaceVulkan::get_native_id() const { +#if defined(VULKAN_ENABLED) + return (void *)vulkan_surface; +#else + return nullptr; +#endif +} + +RenderingContextDriver *RenderingNativeSurfaceVulkan::create_rendering_context(const String &p_driver_name) { +#if defined(VULKAN_ENABLED) + if (p_driver_name == "vulkan") { + return memnew(RenderingContextDriverVulkan); + } +#endif + return nullptr; +} + +RenderingNativeSurfaceVulkan::RenderingNativeSurfaceVulkan() { + // Does nothing. +} + +RenderingNativeSurfaceVulkan::~RenderingNativeSurfaceVulkan() { + // Does nothing. +} diff --git a/drivers/vulkan/rendering_native_surface_vulkan.h b/drivers/vulkan/rendering_native_surface_vulkan.h new file mode 100644 index 000000000000..5b517ec49df8 --- /dev/null +++ b/drivers/vulkan/rendering_native_surface_vulkan.h @@ -0,0 +1,66 @@ +/**************************************************************************/ +/* rendering_native_surface_vulkan.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. */ +/**************************************************************************/ + +#pragma once + +#include "core/variant/native_ptr.h" +#include "servers/rendering/rendering_native_surface.h" + +#ifdef VULKAN_ENABLED +#include "drivers/vulkan/godot_vulkan.h" +#endif + +class RenderingNativeSurfaceVulkan : public RenderingNativeSurface { + GDCLASS(RenderingNativeSurfaceVulkan, RenderingNativeSurface); + + static void _bind_methods(); + +#ifdef VULKAN_ENABLED + VkSurfaceKHR vulkan_surface = VK_NULL_HANDLE; +#endif + +public: + static Ref create_api(GDExtensionConstPtr vulkan_surface); + +#ifdef VULKAN_ENABLED + static Ref create(VkSurfaceKHR vulkan_surface); + + VkSurfaceKHR get_vulkan_surface() const { + return vulkan_surface; + } +#endif + + void *get_native_id() const override; + + RenderingContextDriver *create_rendering_context(const String &p_driver_name) override; + + RenderingNativeSurfaceVulkan(); + ~RenderingNativeSurfaceVulkan(); +}; diff --git a/editor/animation/animation_blend_space_1d_editor.cpp b/editor/animation/animation_blend_space_1d_editor.cpp index 9e09ab6cc857..e299393bedb3 100644 --- a/editor/animation/animation_blend_space_1d_editor.cpp +++ b/editor/animation/animation_blend_space_1d_editor.cpp @@ -814,3 +814,8 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() { set_custom_minimum_size(Size2(0, 150 * EDSCALE)); } + +AnimationNodeBlendSpace1DEditor::~AnimationNodeBlendSpace1DEditor() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} diff --git a/editor/animation/animation_blend_space_1d_editor.h b/editor/animation/animation_blend_space_1d_editor.h index 8a4968d43def..be29dda75dd1 100644 --- a/editor/animation/animation_blend_space_1d_editor.h +++ b/editor/animation/animation_blend_space_1d_editor.h @@ -134,4 +134,5 @@ class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin { virtual bool can_edit(const Ref &p_node) override; virtual void edit(const Ref &p_node) override; AnimationNodeBlendSpace1DEditor(); + ~AnimationNodeBlendSpace1DEditor(); }; diff --git a/editor/animation/animation_blend_space_2d_editor.cpp b/editor/animation/animation_blend_space_2d_editor.cpp index f1701c477f24..e2fb4093f548 100644 --- a/editor/animation/animation_blend_space_2d_editor.cpp +++ b/editor/animation/animation_blend_space_2d_editor.cpp @@ -1101,3 +1101,8 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() { dragging_selected = false; dragging_selected_attempt = false; } + +AnimationNodeBlendSpace2DEditor::~AnimationNodeBlendSpace2DEditor() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} diff --git a/editor/animation/animation_blend_space_2d_editor.h b/editor/animation/animation_blend_space_2d_editor.h index 008356cfa315..42d83ae71789 100644 --- a/editor/animation/animation_blend_space_2d_editor.h +++ b/editor/animation/animation_blend_space_2d_editor.h @@ -145,4 +145,5 @@ class AnimationNodeBlendSpace2DEditor : public AnimationTreeNodeEditorPlugin { virtual bool can_edit(const Ref &p_node) override; virtual void edit(const Ref &p_node) override; AnimationNodeBlendSpace2DEditor(); + ~AnimationNodeBlendSpace2DEditor(); }; diff --git a/editor/animation/animation_blend_tree_editor_plugin.cpp b/editor/animation/animation_blend_tree_editor_plugin.cpp index 4df10d26ac98..f9e7a17d7e70 100644 --- a/editor/animation/animation_blend_tree_editor_plugin.cpp +++ b/editor/animation/animation_blend_tree_editor_plugin.cpp @@ -1285,6 +1285,11 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() { EditorInspector::add_inspector_plugin(animation_node_inspector_plugin); } +AnimationNodeBlendTreeEditor::~AnimationNodeBlendTreeEditor() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} + // EditorPluginAnimationNodeAnimation void AnimationNodeAnimationEditor::_open_set_custom_timeline_from_marker_dialog() { diff --git a/editor/animation/animation_blend_tree_editor_plugin.h b/editor/animation/animation_blend_tree_editor_plugin.h index e11f91280b55..7f669ce9c0a9 100644 --- a/editor/animation/animation_blend_tree_editor_plugin.h +++ b/editor/animation/animation_blend_tree_editor_plugin.h @@ -168,6 +168,7 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin { void update_graph(); AnimationNodeBlendTreeEditor(); + ~AnimationNodeBlendTreeEditor(); }; // EditorPluginAnimationNodeAnimation diff --git a/editor/animation/animation_player_editor_plugin.cpp b/editor/animation/animation_player_editor_plugin.cpp index 38ee401931e3..af1d57db92f5 100644 --- a/editor/animation/animation_player_editor_plugin.cpp +++ b/editor/animation/animation_player_editor_plugin.cpp @@ -2286,6 +2286,8 @@ AnimationPlayerEditor::~AnimationPlayerEditor() { RS::get_singleton()->free(onion.capture.canvas); RS::get_singleton()->free(onion.capture.canvas_item); onion.capture = {}; + ERR_FAIL_COND(singleton != this); + singleton = nullptr; } void AnimationPlayerEditorPlugin::_notification(int p_what) { diff --git a/editor/animation/animation_state_machine_editor.cpp b/editor/animation/animation_state_machine_editor.cpp index 6232150940bb..0b101f59eea4 100644 --- a/editor/animation/animation_state_machine_editor.cpp +++ b/editor/animation/animation_state_machine_editor.cpp @@ -1901,6 +1901,11 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() { open_file->connect("file_selected", callable_mp(this, &AnimationNodeStateMachineEditor::_file_opened)); } +AnimationNodeStateMachineEditor::~AnimationNodeStateMachineEditor() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} + void EditorAnimationMultiTransitionEdit::add_transition(const StringName &p_from, const StringName &p_to, Ref p_transition) { Transition tr; tr.from = p_from; diff --git a/editor/animation/animation_state_machine_editor.h b/editor/animation/animation_state_machine_editor.h index b5ee0fe9cb37..bcacb8c2b26d 100644 --- a/editor/animation/animation_state_machine_editor.h +++ b/editor/animation/animation_state_machine_editor.h @@ -299,6 +299,7 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin { virtual String get_tooltip(const Point2 &p_pos) const override; AnimationNodeStateMachineEditor(); + ~AnimationNodeStateMachineEditor(); }; class EditorAnimationMultiTransitionEdit : public RefCounted { diff --git a/editor/animation/animation_tree_editor_plugin.cpp b/editor/animation/animation_tree_editor_plugin.cpp index f4e9d7d46ada..ea0d8d418dd8 100644 --- a/editor/animation/animation_tree_editor_plugin.cpp +++ b/editor/animation/animation_tree_editor_plugin.cpp @@ -277,6 +277,11 @@ AnimationTreeEditor::AnimationTreeEditor() { add_plugin(memnew(AnimationNodeStateMachineEditor)); } +AnimationTreeEditor::~AnimationTreeEditor() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} + void AnimationTreeEditorPlugin::edit(Object *p_object) { anim_tree_editor->edit(Object::cast_to(p_object)); } diff --git a/editor/animation/animation_tree_editor_plugin.h b/editor/animation/animation_tree_editor_plugin.h index aa081846b7fb..e2426f801c66 100644 --- a/editor/animation/animation_tree_editor_plugin.h +++ b/editor/animation/animation_tree_editor_plugin.h @@ -90,6 +90,7 @@ class AnimationTreeEditor : public VBoxContainer { static AnimationTreeEditor *get_singleton() { return singleton; } void edit(AnimationTree *p_tree); AnimationTreeEditor(); + ~AnimationTreeEditor(); }; class AnimationTreeEditorPlugin : public EditorPlugin { diff --git a/editor/audio/audio_stream_preview.cpp b/editor/audio/audio_stream_preview.cpp index eae31d1aa805..6e9bfcca9204 100644 --- a/editor/audio/audio_stream_preview.cpp +++ b/editor/audio/audio_stream_preview.cpp @@ -253,3 +253,7 @@ AudioStreamPreviewGenerator::AudioStreamPreviewGenerator() { singleton = this; set_process(true); } + +AudioStreamPreviewGenerator::~AudioStreamPreviewGenerator() { + singleton = nullptr; +} diff --git a/editor/audio/audio_stream_preview.h b/editor/audio/audio_stream_preview.h index 47be73b0b316..e361ec7204ad 100644 --- a/editor/audio/audio_stream_preview.h +++ b/editor/audio/audio_stream_preview.h @@ -102,4 +102,5 @@ class AudioStreamPreviewGenerator : public Node { Ref generate_preview(const Ref &p_stream); AudioStreamPreviewGenerator(); + ~AudioStreamPreviewGenerator(); }; diff --git a/editor/debugger/debug_adapter/debug_adapter_protocol.cpp b/editor/debugger/debug_adapter/debug_adapter_protocol.cpp index 6ca69a8bce11..f27f16260ea4 100644 --- a/editor/debugger/debug_adapter/debug_adapter_protocol.cpp +++ b/editor/debugger/debug_adapter/debug_adapter_protocol.cpp @@ -1266,4 +1266,6 @@ DebugAdapterProtocol::DebugAdapterProtocol() { DebugAdapterProtocol::~DebugAdapterProtocol() { memdelete(parser); + ERR_FAIL_COND(singleton != this); + singleton = nullptr; } diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp index 1200787ff3f6..5561c74830f0 100644 --- a/editor/debugger/editor_debugger_node.cpp +++ b/editor/debugger/editor_debugger_node.cpp @@ -100,6 +100,11 @@ EditorDebuggerNode::EditorDebuggerNode() { EditorRunBar::get_singleton()->get_pause_button()->connect(SceneStringName(pressed), callable_mp(this, &EditorDebuggerNode::_paused)); } +EditorDebuggerNode::~EditorDebuggerNode() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} + ScriptEditorDebugger *EditorDebuggerNode::_add_debugger() { ScriptEditorDebugger *node = memnew(ScriptEditorDebugger); diff --git a/editor/debugger/editor_debugger_node.h b/editor/debugger/editor_debugger_node.h index 7e573368f47f..1e0bfd10cbea 100644 --- a/editor/debugger/editor_debugger_node.h +++ b/editor/debugger/editor_debugger_node.h @@ -127,6 +127,7 @@ class EditorDebuggerNode : public MarginContainer { friend class DebugAdapterParser; static EditorDebuggerNode *singleton; EditorDebuggerNode(); + ~EditorDebuggerNode(); protected: void _debugger_stopped(int p_id); diff --git a/editor/docks/editor_dock_manager.cpp b/editor/docks/editor_dock_manager.cpp index ea22f80868cd..28d678f27ee1 100644 --- a/editor/docks/editor_dock_manager.cpp +++ b/editor/docks/editor_dock_manager.cpp @@ -1026,6 +1026,11 @@ EditorDockManager::EditorDockManager() { EditorNode::get_singleton()->get_gui_base()->connect(SceneStringName(theme_changed), callable_mp(this, &EditorDockManager::update_docks_menu)); } +EditorDockManager::~EditorDockManager() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} + //////////////////////////////////////////////// //////////////////////////////////////////////// diff --git a/editor/docks/editor_dock_manager.h b/editor/docks/editor_dock_manager.h index 585c3bc54cc6..e016dc3a86e2 100644 --- a/editor/docks/editor_dock_manager.h +++ b/editor/docks/editor_dock_manager.h @@ -173,6 +173,7 @@ class EditorDockManager : public Object { void set_dock_tab_icon(Control *p_dock, const Ref &p_icon); EditorDockManager(); + ~EditorDockManager(); }; class EditorDockDragHint : public Control { diff --git a/editor/editor_interface.cpp b/editor/editor_interface.cpp index 13c123b999c8..eab681763aaf 100644 --- a/editor/editor_interface.cpp +++ b/editor/editor_interface.cpp @@ -878,6 +878,7 @@ void EditorInterface::create() { void EditorInterface::free() { ERR_FAIL_NULL(singleton); memdelete(singleton); + singleton = nullptr; } EditorInterface::EditorInterface() { diff --git a/editor/editor_undo_redo_manager.cpp b/editor/editor_undo_redo_manager.cpp index 67a557fe5754..76605a00ac69 100644 --- a/editor/editor_undo_redo_manager.cpp +++ b/editor/editor_undo_redo_manager.cpp @@ -572,4 +572,7 @@ EditorUndoRedoManager::~EditorUndoRedoManager() { for (const KeyValue &E : history_map) { discard_history(E.key, false); } + if (singleton == this) { + singleton = nullptr; + } } diff --git a/editor/export/editor_export.cpp b/editor/export/editor_export.cpp index 5e76c5950a3d..9291f4a175ca 100644 --- a/editor/export/editor_export.cpp +++ b/editor/export/editor_export.cpp @@ -451,3 +451,8 @@ EditorExport::EditorExport() { singleton = this; set_process(true); } + +EditorExport::~EditorExport() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} diff --git a/editor/export/editor_export.h b/editor/export/editor_export.h index ec99e92ce7f2..ba7990fc722c 100644 --- a/editor/export/editor_export.h +++ b/editor/export/editor_export.h @@ -83,4 +83,5 @@ class EditorExport : public Node { void connect_presets_runnable_updated(const Callable &p_target); EditorExport(); + ~EditorExport(); }; diff --git a/editor/file_system/editor_file_system.cpp b/editor/file_system/editor_file_system.cpp index d94aae026337..660ad97091de 100644 --- a/editor/file_system/editor_file_system.cpp +++ b/editor/file_system/editor_file_system.cpp @@ -3770,4 +3770,6 @@ EditorFileSystem::~EditorFileSystem() { } filesystem = nullptr; ResourceSaver::set_get_resource_id_for_path(nullptr); + ERR_FAIL_COND(singleton != this); + singleton = nullptr; } diff --git a/editor/gui/progress_dialog.cpp b/editor/gui/progress_dialog.cpp index 5353faf99291..2b7b59fdda2d 100644 --- a/editor/gui/progress_dialog.cpp +++ b/editor/gui/progress_dialog.cpp @@ -302,3 +302,8 @@ ProgressDialog::ProgressDialog() { cancel_hb->add_spacer(); cancel->connect(SceneStringName(pressed), callable_mp(this, &ProgressDialog::_cancel_pressed)); } + +ProgressDialog::~ProgressDialog() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} diff --git a/editor/gui/progress_dialog.h b/editor/gui/progress_dialog.h index 17deeac79c81..f34c0198e8bd 100644 --- a/editor/gui/progress_dialog.h +++ b/editor/gui/progress_dialog.h @@ -105,4 +105,5 @@ class ProgressDialog : public CenterContainer { void remove_host_window(Window *p_window); ProgressDialog(); + ~ProgressDialog(); }; diff --git a/editor/import/3d/scene_import_settings.cpp b/editor/import/3d/scene_import_settings.cpp index c58bea1b2750..47e9e21934de 100644 --- a/editor/import/3d/scene_import_settings.cpp +++ b/editor/import/3d/scene_import_settings.cpp @@ -2009,4 +2009,6 @@ SceneImportSettingsDialog::SceneImportSettingsDialog() { SceneImportSettingsDialog::~SceneImportSettingsDialog() { memdelete(scene_import_settings_data); + ERR_FAIL_COND(singleton != this); + singleton = nullptr; } diff --git a/editor/import/audio_stream_import_settings.cpp b/editor/import/audio_stream_import_settings.cpp index b5cca46e6e36..b5ba07515326 100644 --- a/editor/import/audio_stream_import_settings.cpp +++ b/editor/import/audio_stream_import_settings.cpp @@ -670,3 +670,8 @@ AudioStreamImportSettingsDialog::AudioStreamImportSettingsDialog() { singleton = this; } + +AudioStreamImportSettingsDialog::~AudioStreamImportSettingsDialog() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} diff --git a/editor/import/audio_stream_import_settings.h b/editor/import/audio_stream_import_settings.h index eb6ad2d5baae..9cefb5b409cc 100644 --- a/editor/import/audio_stream_import_settings.h +++ b/editor/import/audio_stream_import_settings.h @@ -110,4 +110,5 @@ class AudioStreamImportSettingsDialog : public ConfirmationDialog { static AudioStreamImportSettingsDialog *get_singleton() { return singleton; } AudioStreamImportSettingsDialog(); + ~AudioStreamImportSettingsDialog(); }; diff --git a/editor/import/dynamic_font_import_settings.cpp b/editor/import/dynamic_font_import_settings.cpp index 94b24fc22906..139a03a5936c 100644 --- a/editor/import/dynamic_font_import_settings.cpp +++ b/editor/import/dynamic_font_import_settings.cpp @@ -1282,3 +1282,8 @@ DynamicFontImportSettingsDialog::DynamicFontImportSettingsDialog() { set_ok_button_text(TTR("Reimport")); set_cancel_button_text(TTR("Close")); } + +DynamicFontImportSettingsDialog::~DynamicFontImportSettingsDialog() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} diff --git a/editor/import/dynamic_font_import_settings.h b/editor/import/dynamic_font_import_settings.h index df4cbe29a31a..fd38da45cb3d 100644 --- a/editor/import/dynamic_font_import_settings.h +++ b/editor/import/dynamic_font_import_settings.h @@ -170,4 +170,5 @@ class DynamicFontImportSettingsDialog : public ConfirmationDialog { static DynamicFontImportSettingsDialog *get_singleton(); DynamicFontImportSettingsDialog(); + ~DynamicFontImportSettingsDialog(); }; diff --git a/editor/import/fbx_importer_manager.cpp b/editor/import/fbx_importer_manager.cpp index 94af76cda9ff..32eb930887b1 100644 --- a/editor/import/fbx_importer_manager.cpp +++ b/editor/import/fbx_importer_manager.cpp @@ -183,3 +183,8 @@ FBXImporterManager::FBXImporterManager() { add_child(browse_dialog); } + +FBXImporterManager::~FBXImporterManager() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} diff --git a/editor/import/fbx_importer_manager.h b/editor/import/fbx_importer_manager.h index 845901fcbc29..f561c8195f4d 100644 --- a/editor/import/fbx_importer_manager.h +++ b/editor/import/fbx_importer_manager.h @@ -63,4 +63,5 @@ class FBXImporterManager : public ConfirmationDialog { void show_dialog(bool p_exclusive = false); FBXImporterManager(); + ~FBXImporterManager(); }; diff --git a/editor/inspector/editor_resource_preview.cpp b/editor/inspector/editor_resource_preview.cpp index f12868a601d9..be5d54ac2d70 100644 --- a/editor/inspector/editor_resource_preview.cpp +++ b/editor/inspector/editor_resource_preview.cpp @@ -610,4 +610,5 @@ EditorResourcePreview::EditorResourcePreview() { EditorResourcePreview::~EditorResourcePreview() { stop(); + singleton = nullptr; } diff --git a/editor/run/editor_run_bar.cpp b/editor/run/editor_run_bar.cpp index c882b7835396..6b144aa7245a 100644 --- a/editor/run/editor_run_bar.cpp +++ b/editor/run/editor_run_bar.cpp @@ -676,3 +676,8 @@ EditorRunBar::EditorRunBar() { write_movie_button->set_tooltip_text(TTRC("Enable Movie Maker mode.\nThe project will run at stable FPS and the visual and audio output will be recorded to a video file.")); write_movie_button->set_accessibility_name(TTRC("Enable Movie Maker Mode")); } + +EditorRunBar::~EditorRunBar() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} diff --git a/editor/run/editor_run_bar.h b/editor/run/editor_run_bar.h index 36b7f4044ad9..27b4942917db 100644 --- a/editor/run/editor_run_bar.h +++ b/editor/run/editor_run_bar.h @@ -137,4 +137,5 @@ class EditorRunBar : public MarginContainer { HBoxContainer *get_buttons_container(); EditorRunBar(); + ~EditorRunBar(); }; diff --git a/editor/run/run_instances_dialog.cpp b/editor/run/run_instances_dialog.cpp index f09ad218bb41..71e668d5d270 100644 --- a/editor/run/run_instances_dialog.cpp +++ b/editor/run/run_instances_dialog.cpp @@ -396,6 +396,11 @@ RunInstancesDialog::RunInstancesDialog() { instance_tree->connect("item_edited", callable_mp(this, &RunInstancesDialog::_start_instance_timer)); } +RunInstancesDialog::~RunInstancesDialog() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} + bool RunInstancesDialog::InstanceData::overrides_run_args() const { return item->is_checked(COLUMN_OVERRIDE_ARGS); } diff --git a/editor/run/run_instances_dialog.h b/editor/run/run_instances_dialog.h index ad2d9da709df..a33f7967f2c0 100644 --- a/editor/run/run_instances_dialog.h +++ b/editor/run/run_instances_dialog.h @@ -102,4 +102,5 @@ class RunInstancesDialog : public AcceptDialog { static RunInstancesDialog *get_singleton() { return singleton; } RunInstancesDialog(); + ~RunInstancesDialog(); }; diff --git a/editor/scene/2d/tiles/tile_set_editor.cpp b/editor/scene/2d/tiles/tile_set_editor.cpp index 7e7df062219a..b73e25e42efd 100644 --- a/editor/scene/2d/tiles/tile_set_editor.cpp +++ b/editor/scene/2d/tiles/tile_set_editor.cpp @@ -974,6 +974,11 @@ TileSetEditor::TileSetEditor() { EditorNode::get_editor_data().add_undo_redo_inspector_hook_callback(callable_mp(this, &TileSetEditor::_undo_redo_inspector_callback)); } +TileSetEditor::~TileSetEditor() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} + void TileSourceInspectorPlugin::_show_id_edit_dialog(Object *p_for_source) { if (!id_edit_dialog) { id_edit_dialog = memnew(ConfirmationDialog); diff --git a/editor/scene/2d/tiles/tile_set_editor.h b/editor/scene/2d/tiles/tile_set_editor.h index 7410c3999ac1..7427abecbbb0 100644 --- a/editor/scene/2d/tiles/tile_set_editor.h +++ b/editor/scene/2d/tiles/tile_set_editor.h @@ -123,6 +123,7 @@ class TileSetEditor : public MarginContainer { void register_split(SplitContainer *p_split); TileSetEditor(); + ~TileSetEditor(); }; class TileSourceInspectorPlugin : public EditorInspectorPlugin { diff --git a/editor/scene/3d/path_3d_editor_plugin.cpp b/editor/scene/3d/path_3d_editor_plugin.cpp index 8ac32394e101..396dc21443fb 100644 --- a/editor/scene/3d/path_3d_editor_plugin.cpp +++ b/editor/scene/3d/path_3d_editor_plugin.cpp @@ -1002,6 +1002,11 @@ Path3DEditorPlugin::Path3DEditorPlugin() { Node3DEditor::get_singleton()->add_control_to_menu_panel(topmenu_bar); } +Path3DEditorPlugin::~Path3DEditorPlugin() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} + Ref Path3DGizmoPlugin::create_gizmo(Node3D *p_spatial) { Ref ref; diff --git a/editor/scene/3d/path_3d_editor_plugin.h b/editor/scene/3d/path_3d_editor_plugin.h index 5526525aafb7..92e8a42f1ecd 100644 --- a/editor/scene/3d/path_3d_editor_plugin.h +++ b/editor/scene/3d/path_3d_editor_plugin.h @@ -186,4 +186,5 @@ class Path3DEditorPlugin : public EditorPlugin { void set_handle_clicked(bool clicked) { handle_clicked = clicked; } Path3DEditorPlugin(); + ~Path3DEditorPlugin(); }; diff --git a/editor/scene/canvas_item_editor_plugin.cpp b/editor/scene/canvas_item_editor_plugin.cpp index 7a73ce9c2c72..12b387791d8a 100644 --- a/editor/scene/canvas_item_editor_plugin.cpp +++ b/editor/scene/canvas_item_editor_plugin.cpp @@ -5809,6 +5809,11 @@ CanvasItemEditor::CanvasItemEditor() { callable_mp(this, &CanvasItemEditor::set_state).call_deferred(get_state()); } +CanvasItemEditor::~CanvasItemEditor() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} + CanvasItemEditor *CanvasItemEditor::singleton = nullptr; void CanvasItemEditorPlugin::edit(Object *p_object) { diff --git a/editor/scene/canvas_item_editor_plugin.h b/editor/scene/canvas_item_editor_plugin.h index 5120dce89967..ef2058c3867f 100644 --- a/editor/scene/canvas_item_editor_plugin.h +++ b/editor/scene/canvas_item_editor_plugin.h @@ -593,6 +593,7 @@ class CanvasItemEditor : public VBoxContainer { EditorSelection *editor_selection = nullptr; CanvasItemEditor(); + ~CanvasItemEditor(); }; class CanvasItemEditorPlugin : public EditorPlugin { diff --git a/editor/scene/editor_scene_tabs.cpp b/editor/scene/editor_scene_tabs.cpp index c9821ed4451b..d957cd55da30 100644 --- a/editor/scene/editor_scene_tabs.cpp +++ b/editor/scene/editor_scene_tabs.cpp @@ -463,3 +463,8 @@ EditorSceneTabs::EditorSceneTabs() { tab_preview->set_position(Point2(2, 2) * EDSCALE); tab_preview_panel->add_child(tab_preview); } + +EditorSceneTabs::~EditorSceneTabs() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} diff --git a/editor/scene/editor_scene_tabs.h b/editor/scene/editor_scene_tabs.h index ee8dce75d644..9a8a0c1c4567 100644 --- a/editor/scene/editor_scene_tabs.h +++ b/editor/scene/editor_scene_tabs.h @@ -104,4 +104,5 @@ class EditorSceneTabs : public MarginContainer { void update_scene_tabs(); EditorSceneTabs(); + ~EditorSceneTabs(); }; diff --git a/editor/scene/gui/control_editor_plugin.cpp b/editor/scene/gui/control_editor_plugin.cpp index 66ae5049099a..c5f85b8ff903 100644 --- a/editor/scene/gui/control_editor_plugin.cpp +++ b/editor/scene/gui/control_editor_plugin.cpp @@ -1148,6 +1148,11 @@ ControlEditorToolbar::ControlEditorToolbar() { singleton = this; } +ControlEditorToolbar::~ControlEditorToolbar() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} + ControlEditorToolbar *ControlEditorToolbar::singleton = nullptr; // Editor plugin. diff --git a/editor/scene/gui/control_editor_plugin.h b/editor/scene/gui/control_editor_plugin.h index b7261770d706..8d89e46e9584 100644 --- a/editor/scene/gui/control_editor_plugin.h +++ b/editor/scene/gui/control_editor_plugin.h @@ -242,6 +242,7 @@ class ControlEditorToolbar : public HBoxContainer { static ControlEditorToolbar *get_singleton() { return singleton; } ControlEditorToolbar(); + ~ControlEditorToolbar(); }; // Editor plugin. diff --git a/editor/settings/editor_build_profile.cpp b/editor/settings/editor_build_profile.cpp index d8579eaf3753..5029a34097e1 100644 --- a/editor/settings/editor_build_profile.cpp +++ b/editor/settings/editor_build_profile.cpp @@ -1369,3 +1369,8 @@ EditorBuildProfileManager::EditorBuildProfileManager() { singleton = this; } + +EditorBuildProfileManager::~EditorBuildProfileManager() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} diff --git a/editor/settings/editor_build_profile.h b/editor/settings/editor_build_profile.h index 4d2c3f212712..fe6aa71c91db 100644 --- a/editor/settings/editor_build_profile.h +++ b/editor/settings/editor_build_profile.h @@ -211,4 +211,5 @@ class EditorBuildProfileManager : public AcceptDialog { static EditorBuildProfileManager *get_singleton() { return singleton; } EditorBuildProfileManager(); + ~EditorBuildProfileManager(); }; diff --git a/editor/settings/editor_feature_profile.cpp b/editor/settings/editor_feature_profile.cpp index 4aa9e9226810..25e2a676cff9 100644 --- a/editor/settings/editor_feature_profile.cpp +++ b/editor/settings/editor_feature_profile.cpp @@ -1072,3 +1072,8 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() { singleton = this; } + +EditorFeatureProfileManager::~EditorFeatureProfileManager() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} diff --git a/editor/settings/editor_feature_profile.h b/editor/settings/editor_feature_profile.h index a57c01dff4d7..feb44e2373cb 100644 --- a/editor/settings/editor_feature_profile.h +++ b/editor/settings/editor_feature_profile.h @@ -183,4 +183,5 @@ class EditorFeatureProfileManager : public AcceptDialog { static EditorFeatureProfileManager *get_singleton() { return singleton; } EditorFeatureProfileManager(); + ~EditorFeatureProfileManager(); }; diff --git a/editor/settings/project_settings_editor.cpp b/editor/settings/project_settings_editor.cpp index 41aa2162586d..b7b8675d0bae 100644 --- a/editor/settings/project_settings_editor.cpp +++ b/editor/settings/project_settings_editor.cpp @@ -856,3 +856,8 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) { MovieWriter::set_extensions_hint(); // ensure extensions are properly displayed. } + +ProjectSettingsEditor::~ProjectSettingsEditor() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} diff --git a/editor/settings/project_settings_editor.h b/editor/settings/project_settings_editor.h index 6263f09549bf..8e3b109b2260 100644 --- a/editor/settings/project_settings_editor.h +++ b/editor/settings/project_settings_editor.h @@ -154,4 +154,5 @@ class ProjectSettingsEditor : public AcceptDialog { void connect_filesystem_dock_signals(FileSystemDock *p_fs_dock); ProjectSettingsEditor(EditorData *p_data); + ~ProjectSettingsEditor(); }; diff --git a/editor/shader/shader_file_editor_plugin.cpp b/editor/shader/shader_file_editor_plugin.cpp index 24e22ce36504..c2beb1309197 100644 --- a/editor/shader/shader_file_editor_plugin.cpp +++ b/editor/shader/shader_file_editor_plugin.cpp @@ -289,6 +289,11 @@ ShaderFileEditor::ShaderFileEditor() { main_vb->add_child(error_text); } +ShaderFileEditor::~ShaderFileEditor() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} + void ShaderFileEditorPlugin::edit(Object *p_object) { RDShaderFile *s = Object::cast_to(p_object); shader_editor->edit(s); diff --git a/editor/shader/shader_file_editor_plugin.h b/editor/shader/shader_file_editor_plugin.h index 06e31016b763..026406735aca 100644 --- a/editor/shader/shader_file_editor_plugin.h +++ b/editor/shader/shader_file_editor_plugin.h @@ -63,6 +63,7 @@ class ShaderFileEditor : public PanelContainer { void edit(const Ref &p_shader); ShaderFileEditor(); + ~ShaderFileEditor(); }; class ShaderFileEditorPlugin : public EditorPlugin { diff --git a/editor/version_control/version_control_editor_plugin.cpp b/editor/version_control/version_control_editor_plugin.cpp index 6d7f4a0beef9..061cbc94dd4b 100644 --- a/editor/version_control/version_control_editor_plugin.cpp +++ b/editor/version_control/version_control_editor_plugin.cpp @@ -1528,4 +1528,6 @@ VersionControlEditorPlugin::~VersionControlEditorPlugin() { memdelete(version_commit_dock); memdelete(version_control_dock); memdelete(version_control_actions); + ERR_FAIL_COND(singleton != this); + singleton = nullptr; } diff --git a/main/main.cpp b/main/main.cpp index 62dafe881d4a..f656e23d4b86 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -790,6 +790,7 @@ Error Main::test_setup() { ClassDB::set_current_api(ClassDB::API_CORE); #endif + register_core_platform_apis(); register_platform_apis(); // Theme needs modules to be initialized so that sub-resources can be loaded. @@ -850,6 +851,7 @@ void Main::test_cleanup() { uninitialize_modules(MODULE_INITIALIZATION_LEVEL_SCENE); unregister_platform_apis(); + unregister_core_platform_apis(); unregister_driver_types(); unregister_scene_types(); @@ -865,6 +867,7 @@ void Main::test_cleanup() { GDExtensionManager::get_singleton()->deinitialize_extensions(GDExtension::INITIALIZATION_LEVEL_SERVERS); uninitialize_modules(MODULE_INITIALIZATION_LEVEL_SERVERS); unregister_server_types(); + unregister_core_server_types(); EngineDebugger::deinitialize(); OS::get_singleton()->finalize(); @@ -976,6 +979,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph register_core_types(); register_core_driver_types(); + register_core_platform_apis(); + MAIN_PRINT("Main: Initialize Globals"); input_map = memnew(InputMap); @@ -2823,6 +2828,9 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph message_queue = memnew(MessageQueue); + // Register Core Server Types + register_core_server_types(); + Thread::release_main_thread(); // If setup2() is called from another thread, that one will become main thread, so preventively release this one. set_current_thread_safe_for_nodes(false); @@ -2881,6 +2889,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph memdelete(packed_data); } + unregister_core_platform_apis(); unregister_core_driver_types(); unregister_core_extensions(); @@ -3809,7 +3818,8 @@ void Main::setup_boot_logo() { boot_bg_color = GLOBAL_DEF_BASIC("application/boot_splash/bg_color", (editor || project_manager) ? boot_splash_editor_bg_color : boot_splash_bg_color); #endif if (boot_logo.is_valid()) { - RenderingServer::get_singleton()->set_boot_image(boot_logo, boot_bg_color, boot_logo_scale, boot_logo_filter); + RenderingServer::get_singleton()->set_boot_image(boot_logo, boot_bg_color, boot_logo_scale, DisplayServer::MAIN_WINDOW_ID, + boot_logo_filter); } else { #ifndef NO_DEFAULT_BOOT_LOGO @@ -3823,7 +3833,7 @@ void Main::setup_boot_logo() { MAIN_PRINT("Main: ClearColor"); RenderingServer::get_singleton()->set_default_clear_color(boot_bg_color); MAIN_PRINT("Main: Image"); - RenderingServer::get_singleton()->set_boot_image(splash, boot_bg_color, false); + RenderingServer::get_singleton()->set_boot_image(splash, boot_bg_color, false, DisplayServer::MAIN_WINDOW_ID); #endif } @@ -5038,6 +5048,7 @@ void Main::cleanup(bool p_force) { GDExtensionManager::get_singleton()->deinitialize_extensions(GDExtension::INITIALIZATION_LEVEL_SERVERS); uninitialize_modules(MODULE_INITIALIZATION_LEVEL_SERVERS); unregister_server_types(); + unregister_core_server_types(); EngineDebugger::deinitialize(); diff --git a/main/performance.cpp b/main/performance.cpp index 8f0bedbde67e..4b9558141c59 100644 --- a/main/performance.cpp +++ b/main/performance.cpp @@ -573,6 +573,11 @@ Performance::Performance() { singleton = this; } +Performance::~Performance() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} + Performance::MonitorCall::MonitorCall(Callable p_callable, Vector p_arguments) { _callable = p_callable; _arguments = p_arguments; diff --git a/main/performance.h b/main/performance.h index 0fdac285cd7d..7911570ef6be 100644 --- a/main/performance.h +++ b/main/performance.h @@ -154,6 +154,7 @@ class Performance : public Object { static Performance *get_singleton() { return singleton; } Performance(); + ~Performance(); }; VARIANT_ENUM_CAST(Performance::Monitor); diff --git a/modules/gdscript/language_server/gdscript_language_protocol.cpp b/modules/gdscript/language_server/gdscript_language_protocol.cpp index 7e19fa8e731a..91d61487c6e5 100644 --- a/modules/gdscript/language_server/gdscript_language_protocol.cpp +++ b/modules/gdscript/language_server/gdscript_language_protocol.cpp @@ -400,6 +400,11 @@ GDScriptLanguageProtocol::GDScriptLanguageProtocol() { workspace->root = ProjectSettings::get_singleton()->get_resource_path(); } +GDScriptLanguageProtocol::~GDScriptLanguageProtocol() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} + #undef SET_DOCUMENT_METHOD #undef SET_COMPLETION_METHOD #undef SET_WORKSPACE_METHOD diff --git a/modules/gdscript/language_server/gdscript_language_protocol.h b/modules/gdscript/language_server/gdscript_language_protocol.h index afdd849b8d9b..8d2123f2643f 100644 --- a/modules/gdscript/language_server/gdscript_language_protocol.h +++ b/modules/gdscript/language_server/gdscript_language_protocol.h @@ -108,4 +108,5 @@ class GDScriptLanguageProtocol : public JSONRPC { bool is_goto_native_symbols_enabled() const; GDScriptLanguageProtocol(); + ~GDScriptLanguageProtocol(); }; diff --git a/modules/gltf/editor/editor_import_blend_runner.cpp b/modules/gltf/editor/editor_import_blend_runner.cpp index 7b99ba656c44..dfeb53b97b76 100644 --- a/modules/gltf/editor/editor_import_blend_runner.cpp +++ b/modules/gltf/editor/editor_import_blend_runner.cpp @@ -388,3 +388,8 @@ EditorImportBlendRunner::EditorImportBlendRunner() { EditorFileSystem::get_singleton()->connect("resources_reimported", callable_mp(this, &EditorImportBlendRunner::_resources_reimported)); } + +EditorImportBlendRunner::~EditorImportBlendRunner() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} diff --git a/modules/gltf/editor/editor_import_blend_runner.h b/modules/gltf/editor/editor_import_blend_runner.h index c2a087b719dc..61a9fb1e3e2b 100644 --- a/modules/gltf/editor/editor_import_blend_runner.h +++ b/modules/gltf/editor/editor_import_blend_runner.h @@ -62,4 +62,5 @@ class EditorImportBlendRunner : public Node { HTTPClient::Status connect_blender_rpc(const Ref &p_client, int p_timeout_usecs); EditorImportBlendRunner(); + ~EditorImportBlendRunner(); }; diff --git a/modules/godot_physics_2d/godot_physics_server_2d.cpp b/modules/godot_physics_2d/godot_physics_server_2d.cpp index 47df6a252671..8c05af2bdee5 100644 --- a/modules/godot_physics_2d/godot_physics_server_2d.cpp +++ b/modules/godot_physics_2d/godot_physics_server_2d.cpp @@ -1397,3 +1397,8 @@ GodotPhysicsServer2D::GodotPhysicsServer2D(bool p_using_threads) { using_threads = p_using_threads; } + +GodotPhysicsServer2D::~GodotPhysicsServer2D() { + ERR_FAIL_COND(godot_singleton != this); + godot_singleton = nullptr; +} diff --git a/modules/godot_physics_2d/godot_physics_server_2d.h b/modules/godot_physics_2d/godot_physics_server_2d.h index 4e7eb23d1837..0fa1d792d2cc 100644 --- a/modules/godot_physics_2d/godot_physics_server_2d.h +++ b/modules/godot_physics_2d/godot_physics_server_2d.h @@ -300,5 +300,5 @@ class GodotPhysicsServer2D : public PhysicsServer2D { int get_process_info(ProcessInfo p_info) override; GodotPhysicsServer2D(bool p_using_threads = false); - ~GodotPhysicsServer2D() {} + ~GodotPhysicsServer2D(); }; diff --git a/modules/godot_physics_3d/godot_physics_server_3d.cpp b/modules/godot_physics_3d/godot_physics_server_3d.cpp index d5f12857d9e2..5ad9a59d9225 100644 --- a/modules/godot_physics_3d/godot_physics_server_3d.cpp +++ b/modules/godot_physics_3d/godot_physics_server_3d.cpp @@ -1813,3 +1813,8 @@ GodotPhysicsServer3D::GodotPhysicsServer3D(bool p_using_threads) { using_threads = p_using_threads; } + +GodotPhysicsServer3D::~GodotPhysicsServer3D() { + ERR_FAIL_COND(godot_singleton != this); + godot_singleton = nullptr; +} diff --git a/modules/godot_physics_3d/godot_physics_server_3d.h b/modules/godot_physics_3d/godot_physics_server_3d.h index 23c5d1b49ce5..58f1f2fc1bbe 100644 --- a/modules/godot_physics_3d/godot_physics_server_3d.h +++ b/modules/godot_physics_3d/godot_physics_server_3d.h @@ -386,5 +386,5 @@ class GodotPhysicsServer3D : public PhysicsServer3D { int get_process_info(ProcessInfo p_info) override; GodotPhysicsServer3D(bool p_using_threads = false); - ~GodotPhysicsServer3D() {} + ~GodotPhysicsServer3D(); }; diff --git a/modules/navigation_2d/2d/nav_mesh_generator_2d.cpp b/modules/navigation_2d/2d/nav_mesh_generator_2d.cpp index 191a2ee4c57c..4b301dfe144b 100644 --- a/modules/navigation_2d/2d/nav_mesh_generator_2d.cpp +++ b/modules/navigation_2d/2d/nav_mesh_generator_2d.cpp @@ -68,6 +68,8 @@ NavMeshGenerator2D::NavMeshGenerator2D() { NavMeshGenerator2D::~NavMeshGenerator2D() { cleanup(); + ERR_FAIL_COND(singleton != this); + singleton = nullptr; } void NavMeshGenerator2D::sync() { diff --git a/modules/navigation_3d/3d/nav_mesh_generator_3d.cpp b/modules/navigation_3d/3d/nav_mesh_generator_3d.cpp index 9fe3a278e22b..073ea0f0714f 100644 --- a/modules/navigation_3d/3d/nav_mesh_generator_3d.cpp +++ b/modules/navigation_3d/3d/nav_mesh_generator_3d.cpp @@ -83,6 +83,8 @@ NavMeshGenerator3D::NavMeshGenerator3D() { NavMeshGenerator3D::~NavMeshGenerator3D() { cleanup(); + ERR_FAIL_COND(singleton != this); + singleton = nullptr; } void NavMeshGenerator3D::sync() { diff --git a/modules/navigation_3d/3d/navigation_mesh_generator.cpp b/modules/navigation_3d/3d/navigation_mesh_generator.cpp index 496bded0c358..594ae28893cb 100644 --- a/modules/navigation_3d/3d/navigation_mesh_generator.cpp +++ b/modules/navigation_3d/3d/navigation_mesh_generator.cpp @@ -44,6 +44,8 @@ NavigationMeshGenerator::NavigationMeshGenerator() { } NavigationMeshGenerator::~NavigationMeshGenerator() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; } void NavigationMeshGenerator::bake(const Ref &p_navigation_mesh, Node *p_root_node) { diff --git a/modules/navigation_3d/editor/navigation_obstacle_3d_editor_plugin.cpp b/modules/navigation_3d/editor/navigation_obstacle_3d_editor_plugin.cpp index 7e659465c8c0..bfe31c1f5c6d 100644 --- a/modules/navigation_3d/editor/navigation_obstacle_3d_editor_plugin.cpp +++ b/modules/navigation_3d/editor/navigation_obstacle_3d_editor_plugin.cpp @@ -898,4 +898,6 @@ NavigationObstacle3DEditorPlugin::~NavigationObstacle3DEditorPlugin() { rs->free(point_handle_mesh_rid); point_handle_mesh_rid = RID(); } + ERR_FAIL_COND(singleton != this); + singleton = nullptr; } diff --git a/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.cpp b/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.cpp index 402389144abc..02a8d31c519c 100644 --- a/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.cpp +++ b/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.cpp @@ -43,6 +43,8 @@ OpenXRDisplayRefreshRateExtension::OpenXRDisplayRefreshRateExtension() { OpenXRDisplayRefreshRateExtension::~OpenXRDisplayRefreshRateExtension() { display_refresh_rate_ext = false; + ERR_FAIL_COND(singleton != this); + singleton = nullptr; } HashMap OpenXRDisplayRefreshRateExtension::get_requested_extensions() { diff --git a/modules/regex/SCsub b/modules/regex/SCsub index 979995ef5135..e1186a4f64d7 100644 --- a/modules/regex/SCsub +++ b/modules/regex/SCsub @@ -72,7 +72,7 @@ if env["builtin_pcre2"]: module_obj = [] -env_regex.Append(CPPDEFINES=[("PCRE2_CODE_UNIT_WIDTH", 0)]) +env_regex.Append(CPPDEFINES=[("PCRE2_CODE_UNIT_WIDTH", 16)]) env_regex.add_source_files(module_obj, "*.cpp") env.modules_sources += module_obj diff --git a/platform/android/SCsub b/platform/android/SCsub index f97ad7a8a701..0192011dca1a 100644 --- a/platform/android/SCsub +++ b/platform/android/SCsub @@ -30,6 +30,7 @@ android_files = [ "display_server_android.cpp", "plugin/godot_plugin_jni.cpp", "rendering_context_driver_vulkan_android.cpp", + "rendering_native_surface_android.cpp", "variant/callable_jni.cpp", "dialog_utils_jni.cpp", "editor/game_menu_utils_jni.cpp", diff --git a/platform/android/api/api.cpp b/platform/android/api/api.cpp index 86051a87f3b4..fb1dee53022a 100644 --- a/platform/android/api/api.cpp +++ b/platform/android/api/api.cpp @@ -34,11 +34,21 @@ #include "jni_singleton.h" #include "core/config/engine.h" +#include "platform/android/rendering_native_surface_android.h" #if !defined(ANDROID_ENABLED) static JavaClassWrapper *java_class_wrapper = nullptr; #endif +void register_core_android_api() { +#if defined(ANDROID_ENABLED) + GDREGISTER_ABSTRACT_CLASS(RenderingNativeSurfaceAndroid); +#endif +} + +void unregister_core_android_api() { +} + void register_android_api() { #if !defined(ANDROID_ENABLED) // On Android platforms, the `java_class_wrapper` instantiation occurs in @@ -118,4 +128,9 @@ JavaClassWrapper::JavaClassWrapper() { singleton = this; } +JavaClassWrapper::~JavaClassWrapper() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} + #endif diff --git a/platform/android/api/api.h b/platform/android/api/api.h index 2be6c59b3dff..f902e02aa7e5 100644 --- a/platform/android/api/api.h +++ b/platform/android/api/api.h @@ -30,5 +30,7 @@ #pragma once +void register_core_android_api(); +void unregister_core_android_api(); void register_android_api(); void unregister_android_api(); diff --git a/platform/android/api/java_class_wrapper.h b/platform/android/api/java_class_wrapper.h index de04c80723b4..a6016d3204be 100644 --- a/platform/android/api/java_class_wrapper.h +++ b/platform/android/api/java_class_wrapper.h @@ -294,4 +294,5 @@ class JavaClassWrapper : public Object { Ref wrap_jclass(jclass p_class, bool p_allow_private_methods_access = false); #endif JavaClassWrapper(); + ~JavaClassWrapper(); }; diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp index c303edf1e61e..197ba66d340a 100644 --- a/platform/android/display_server_android.cpp +++ b/platform/android/display_server_android.cpp @@ -40,10 +40,6 @@ #if defined(RD_ENABLED) #include "servers/rendering/renderer_rd/renderer_compositor_rd.h" #include "servers/rendering/rendering_device.h" - -#if defined(VULKAN_ENABLED) -#include "rendering_context_driver_vulkan_android.h" -#endif #endif #ifdef GLES3_ENABLED @@ -674,20 +670,16 @@ void DisplayServerAndroid::reset_window() { VSyncMode last_vsync_mode = rendering_context->window_get_vsync_mode(MAIN_WINDOW_ID); rendering_context->window_destroy(MAIN_WINDOW_ID); - union { -#ifdef VULKAN_ENABLED - RenderingContextDriverVulkanAndroid::WindowPlatformData vulkan; -#endif - } wpd; + Ref android_surface; #ifdef VULKAN_ENABLED if (rendering_driver == "vulkan") { ANativeWindow *native_window = OS_Android::get_singleton()->get_native_window(); ERR_FAIL_NULL(native_window); - wpd.vulkan.window = native_window; + android_surface = RenderingNativeSurfaceAndroid::create(native_window); } #endif - if (rendering_context->window_create(MAIN_WINDOW_ID, &wpd) != OK) { + if (rendering_context->window_create(MAIN_WINDOW_ID, android_surface) != OK) { ERR_PRINT(vformat("Failed to reset %s window.", rendering_driver)); memdelete(rendering_context); rendering_context = nullptr; @@ -722,12 +714,19 @@ DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, Dis rendering_context = nullptr; rendering_device = nullptr; -#if defined(VULKAN_ENABLED) + Ref android_surface; +#ifdef VULKAN_ENABLED if (rendering_driver == "vulkan") { - rendering_context = memnew(RenderingContextDriverVulkanAndroid); + ANativeWindow *native_window = OS_Android::get_singleton()->get_native_window(); + ERR_FAIL_NULL(native_window); + android_surface = RenderingNativeSurfaceAndroid::create(native_window); } #endif + if (android_surface.is_valid()) { + rendering_context = android_surface->create_rendering_context(rendering_driver); + } + if (rendering_context) { if (rendering_context->initialize() != OK) { memdelete(rendering_context); @@ -750,20 +749,7 @@ DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, Dis } if (rendering_context) { - union { -#ifdef VULKAN_ENABLED - RenderingContextDriverVulkanAndroid::WindowPlatformData vulkan; -#endif - } wpd; -#ifdef VULKAN_ENABLED - if (rendering_driver == "vulkan") { - ANativeWindow *native_window = OS_Android::get_singleton()->get_native_window(); - ERR_FAIL_NULL(native_window); - wpd.vulkan.window = native_window; - } -#endif - - if (rendering_context->window_create(MAIN_WINDOW_ID, &wpd) != OK) { + if (rendering_context->window_create(MAIN_WINDOW_ID, android_surface) != OK) { ERR_PRINT(vformat("Failed to create %s window.", rendering_driver)); memdelete(rendering_context); rendering_context = nullptr; diff --git a/platform/android/java_class_wrapper.cpp b/platform/android/java_class_wrapper.cpp index 8339ff6ae3a5..fe74397b893d 100644 --- a/platform/android/java_class_wrapper.cpp +++ b/platform/android/java_class_wrapper.cpp @@ -1757,3 +1757,8 @@ JavaClassWrapper::JavaClassWrapper() { Double_doubleValue = env->GetMethodID(bclass, "doubleValue", "()D"); env->DeleteLocalRef(bclass); } + +JavaClassWrapper::~JavaClassWrapper() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} diff --git a/platform/android/os_android.h b/platform/android/os_android.h index c4a8c8f02b23..f3507317a7db 100644 --- a/platform/android/os_android.h +++ b/platform/android/os_android.h @@ -101,6 +101,9 @@ class OS_Android : public OS_Unix { virtual void initialize_joypads() override; + virtual Error set_cwd(const String &p_cwd) override; + String get_asset_path_prefix() { return asset_path_prefix; } + virtual void set_main_loop(MainLoop *p_main_loop) override; virtual void delete_main_loop() override; diff --git a/platform/android/rendering_context_driver_vulkan_android.cpp b/platform/android/rendering_context_driver_vulkan_android.cpp index 51fb1ca18fa8..522024d7d6a4 100644 --- a/platform/android/rendering_context_driver_vulkan_android.cpp +++ b/platform/android/rendering_context_driver_vulkan_android.cpp @@ -29,6 +29,8 @@ /**************************************************************************/ #include "rendering_context_driver_vulkan_android.h" +#include "drivers/vulkan/rendering_native_surface_vulkan.h" +#include "rendering_native_surface_android.h" #ifdef VULKAN_ENABLED @@ -38,8 +40,9 @@ const char *RenderingContextDriverVulkanAndroid::_get_platform_surface_extension return VK_KHR_ANDROID_SURFACE_EXTENSION_NAME; } -RenderingContextDriver::SurfaceID RenderingContextDriverVulkanAndroid::surface_create(const void *p_platform_data) { - const WindowPlatformData *wpd = (const WindowPlatformData *)(p_platform_data); +RenderingContextDriver::SurfaceID RenderingContextDriverVulkanAndroid::surface_create(Ref p_native_surface) { + Ref android_native_surface = Object::cast_to(*p_native_surface); + ERR_FAIL_COND_V(android_native_surface.is_null(), SurfaceID()); VkAndroidSurfaceCreateInfoKHR create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; @@ -49,9 +52,10 @@ RenderingContextDriver::SurfaceID RenderingContextDriverVulkanAndroid::surface_c VkResult err = vkCreateAndroidSurfaceKHR(instance_get(), &create_info, get_allocation_callbacks(VK_OBJECT_TYPE_SURFACE_KHR), &vk_surface); ERR_FAIL_COND_V(err != VK_SUCCESS, SurfaceID()); - Surface *surface = memnew(Surface); - surface->vk_surface = vk_surface; - return SurfaceID(surface); + Ref vulkan_surface = RenderingNativeSurfaceVulkan::create(vk_surface); + RenderingContextDriver::SurfaceID result = RenderingContextDriverVulkan::surface_create(vulkan_surface); + memdelete(vulkan_surface); + return result; } bool RenderingContextDriverVulkanAndroid::_use_validation_layers() const { diff --git a/platform/android/rendering_context_driver_vulkan_android.h b/platform/android/rendering_context_driver_vulkan_android.h index bd50e4ebb73c..a7d5ec941409 100644 --- a/platform/android/rendering_context_driver_vulkan_android.h +++ b/platform/android/rendering_context_driver_vulkan_android.h @@ -41,14 +41,10 @@ class RenderingContextDriverVulkanAndroid : public RenderingContextDriverVulkan virtual const char *_get_platform_surface_extension() const override final; protected: - SurfaceID surface_create(const void *p_platform_data) override final; + SurfaceID surface_create(Ref p_native_surface) override final; bool _use_validation_layers() const override final; public: - struct WindowPlatformData { - ANativeWindow *window; - }; - RenderingContextDriverVulkanAndroid() = default; ~RenderingContextDriverVulkanAndroid() override = default; }; diff --git a/platform/macos/rendering_context_driver_vulkan_macos.mm b/platform/android/rendering_native_surface_android.cpp similarity index 65% rename from platform/macos/rendering_context_driver_vulkan_macos.mm rename to platform/android/rendering_native_surface_android.cpp index f95671526369..fe6811612710 100644 --- a/platform/macos/rendering_context_driver_vulkan_macos.mm +++ b/platform/android/rendering_native_surface_android.cpp @@ -1,5 +1,5 @@ /**************************************************************************/ -/* rendering_context_driver_vulkan_macos.mm */ +/* rendering_native_surface_android.cpp */ /**************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,42 +28,40 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ +#include "rendering_native_surface_android.h" #import "rendering_context_driver_vulkan_macos.h" -#ifdef VULKAN_ENABLED - -#ifdef USE_VOLK -#include -#else -#include +#if defined(VULKAN_ENABLED) +#include "rendering_context_driver_vulkan_android.h" #endif -const char *RenderingContextDriverVulkanMacOS::_get_platform_surface_extension() const { - return VK_EXT_METAL_SURFACE_EXTENSION_NAME; +void RenderingNativeSurfaceAndroid::_bind_methods() { + ClassDB::bind_static_method("RenderingNativeSurfaceAndroid", D_METHOD("create", "window"), &RenderingNativeSurfaceAndroid::create_api); } -RenderingContextDriver::SurfaceID RenderingContextDriverVulkanMacOS::surface_create(const void *p_platform_data) { - const WindowPlatformData *wpd = (const WindowPlatformData *)(p_platform_data); - - VkMetalSurfaceCreateInfoEXT create_info = {}; - create_info.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT; - create_info.pLayer = *wpd->layer_ptr; +Ref RenderingNativeSurfaceAndroid::create_api(GDExtensionConstPtr p_window) { + return RenderingNativeSurfaceAndroid::create((ANativeWindow *)p_window.operator const void *()); +} - VkSurfaceKHR vk_surface = VK_NULL_HANDLE; - VkResult err = vkCreateMetalSurfaceEXT(instance_get(), &create_info, get_allocation_callbacks(VK_OBJECT_TYPE_SURFACE_KHR), &vk_surface); - ERR_FAIL_COND_V(err != VK_SUCCESS, SurfaceID()); +Ref RenderingNativeSurfaceAndroid::create(ANativeWindow *p_window) { + Ref result = memnew(RenderingNativeSurfaceAndroid); + result->window = p_window; + return result; +} - Surface *surface = memnew(Surface); - surface->vk_surface = vk_surface; - return SurfaceID(surface); +RenderingContextDriver *RenderingNativeSurfaceAndroid::create_rendering_context(const String &p_driver_name) { +#if defined(VULKAN_ENABLED) + if (p_driver_name == "vulkan") { + return memnew(RenderingContextDriverVulkanAndroid); + } +#endif + return nullptr; } -RenderingContextDriverVulkanMacOS::RenderingContextDriverVulkanMacOS() { +RenderingNativeSurfaceAndroid::RenderingNativeSurfaceAndroid() { // Does nothing. } -RenderingContextDriverVulkanMacOS::~RenderingContextDriverVulkanMacOS() { +RenderingNativeSurfaceAndroid::~RenderingNativeSurfaceAndroid() { // Does nothing. } - -#endif // VULKAN_ENABLED diff --git a/platform/android/rendering_native_surface_android.h b/platform/android/rendering_native_surface_android.h new file mode 100644 index 000000000000..500c732ebabb --- /dev/null +++ b/platform/android/rendering_native_surface_android.h @@ -0,0 +1,58 @@ +/**************************************************************************/ +/* rendering_native_surface_android.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. */ +/**************************************************************************/ + +#pragma once + +#include "core/variant/native_ptr.h" +#include "servers/rendering/rendering_native_surface.h" + +struct ANativeWindow; + +class RenderingNativeSurfaceAndroid : public RenderingNativeSurface { + GDCLASS(RenderingNativeSurfaceAndroid, RenderingNativeSurface); + + static void _bind_methods(); + + ANativeWindow *window; + +public: + static Ref create_api(GDExtensionConstPtr p_window); + + static Ref create(ANativeWindow *p_window); + + ANativeWindow *get_window() const { + return window; + } + + RenderingContextDriver *create_rendering_context(const String &p_driver_name) override; + + RenderingNativeSurfaceAndroid(); + ~RenderingNativeSurfaceAndroid(); +}; diff --git a/platform/ios/SCsub b/platform/ios/SCsub index a313442e2ae3..65bfc432b537 100644 --- a/platform/ios/SCsub +++ b/platform/ios/SCsub @@ -7,17 +7,32 @@ from platform_methods import combine_libs_apple_embedded Import("env") -ios_lib = [ + +common_ios_lib_files = [ + "os_ios.mm", +] + +ios_lib_files = [ "device_metrics.mm", "display_layer_ios.mm", "display_server_ios.mm", "godot_view_ios.mm", "main_ios.mm", - "os_ios.mm", + "view_controller.mm", + "godot_view_renderer.mm", + "keyboard_input_view.mm", +] + +ios_libgodot_files = [ + "libgodot_ios.mm", ] env_ios = env.Clone() -ios_lib = env_ios.add_library("ios", ios_lib) + +if env["library_type"] != "executable": + ios_lib = env_ios.add_library("ios", common_ios_lib_files + ios_libgodot_files) +else: + ios_lib = env_ios.add_library("ios", common_ios_lib_files + ios_lib_files) # (iOS) Enable module support env_ios.Append(CCFLAGS=["-fmodules", "-fcxx-modules"]) diff --git a/platform/ios/api/api.cpp b/platform/ios/api/api.cpp index 9de39616c0f2..b929d086ba5c 100644 --- a/platform/ios/api/api.cpp +++ b/platform/ios/api/api.cpp @@ -32,16 +32,31 @@ #if defined(IOS_ENABLED) +#include "drivers/apple/rendering_native_surface_apple.h" + +void register_core_ios_api() { + GDREGISTER_ABSTRACT_CLASS(RenderingNativeSurfaceApple); +} + +void unregister_core_ios_api() { +} + void register_ios_api() { +#ifndef LIBGODOT_ENABLED godot_apple_embedded_plugins_initialize(); +#endif } void unregister_ios_api() { +#ifndef LIBGODOT_ENABLED godot_apple_embedded_plugins_deinitialize(); +#endif } #else +void register_core_ios_api() {} +void unregister_core_ios_api() {} void register_ios_api() {} void unregister_ios_api() {} diff --git a/platform/ios/api/api.h b/platform/ios/api/api.h index 393df2cafb86..c077ccd46b8c 100644 --- a/platform/ios/api/api.h +++ b/platform/ios/api/api.h @@ -35,5 +35,7 @@ extern void godot_apple_embedded_plugins_initialize(); extern void godot_apple_embedded_plugins_deinitialize(); #endif +void register_core_ios_api(); +void unregister_core_ios_api(); void register_ios_api(); void unregister_ios_api(); diff --git a/platform/ios/detect.py b/platform/ios/detect.py index f996bf7781c5..cd5686d5ea8b 100644 --- a/platform/ios/detect.py +++ b/platform/ios/detect.py @@ -31,6 +31,7 @@ def get_opts(): (("apple_target_triple", "ios_triple"), "Triple for the corresponding target Apple platform toolchain", ""), BoolVariable(("simulator", "ios_simulator"), "Build for Simulator", False), BoolVariable("generate_bundle", "Generate an APP bundle after building iOS/macOS binaries", False), + BoolVariable("coreaudio_enabled", "Coreaudio Enabled", True), ] @@ -147,11 +148,10 @@ def configure(env: "SConsEnvironment"): ) env.Prepend(CPPPATH=["#platform/ios"]) - env.Append(CPPDEFINES=["IOS_ENABLED", "APPLE_EMBEDDED_ENABLED", "UNIX_ENABLED", "COREAUDIO_ENABLED"]) + env.Append(CPPDEFINES=["IOS_ENABLED", "UNIX_ENABLED", "APPLE_EMBEDDED_ENABLED"]) - if env["metal"] and env["simulator"]: - print_warning("iOS Simulator does not support the Metal rendering driver") - env["metal"] = False + if env["coreaudio_enabled"]: + env.Append(CPPDEFINES=["COREAUDIO_ENABLED"]) if env["metal"]: env.AppendUnique(CPPDEFINES=["METAL_ENABLED", "RD_ENABLED"]) diff --git a/platform/ios/display_layer_ios.h b/platform/ios/display_layer_ios.h index 14977b3204fd..71a173a9c83c 100644 --- a/platform/ios/display_layer_ios.h +++ b/platform/ios/display_layer_ios.h @@ -33,6 +33,7 @@ #include "drivers/apple_embedded/display_layer_apple_embedded.h" #import +#import #import // An ugly workaround for iOS simulator diff --git a/platform/ios/display_layer_ios.mm b/platform/ios/display_layer_ios.mm index 1c7e27c1f6c0..28fb5f458828 100644 --- a/platform/ios/display_layer_ios.mm +++ b/platform/ios/display_layer_ios.mm @@ -41,7 +41,6 @@ #import #import #import -#import #import #import #import @@ -67,16 +66,14 @@ - (void)startRenderDisplayLayer { - (void)stopRenderDisplayLayer { } +- (void)setupContext:(GLManager *)context withSurface:(Ref *)surface { +} + @end @implementation GDTOpenGLLayer { - // The pixel dimensions of the backbuffer - GLint backingWidth; - GLint backingHeight; - - EAGLContext *context; - GLuint viewRenderbuffer, viewFramebuffer; - GLuint depthRenderbuffer; + GLManager *gl_manager; + Ref native_surface; } - (void)initializeDisplayLayer { @@ -88,104 +85,29 @@ - (void)initializeDisplayLayer { kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil]; - - // Create GL ES 3 context - if (GLOBAL_GET("rendering/renderer/rendering_method") == "gl_compatibility") { - context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3]; - NSLog(@"Setting up an OpenGL ES 3.0 context."); - if (!context) { - NSLog(@"Failed to create OpenGL ES 3.0 context!"); - return; - } - } - - if (![EAGLContext setCurrentContext:context]) { - NSLog(@"Failed to set EAGLContext!"); - return; - } - if (![self createFramebuffer]) { - NSLog(@"Failed to create frame buffer!"); - return; - } } - (void)layoutDisplayLayer { - [EAGLContext setCurrentContext:context]; - [self destroyFramebuffer]; - [self createFramebuffer]; + gl_manager->window_resize(DisplayServer::MAIN_WINDOW_ID, 0, 0); } - (void)startRenderDisplayLayer { - [EAGLContext setCurrentContext:context]; - - glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer); + gl_manager->window_make_current(DisplayServer::MAIN_WINDOW_ID); } - (void)stopRenderDisplayLayer { - glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); - [context presentRenderbuffer:GL_RENDERBUFFER_OES]; - -#ifdef DEBUG_ENABLED - GLenum err = glGetError(); - if (err) { - NSLog(@"DrawView: %x error", err); - } -#endif + gl_manager->swap_buffers(); } - (void)dealloc { - if ([EAGLContext currentContext] == context) { - [EAGLContext setCurrentContext:nil]; - } - - if (context) { - context = nil; - } + gl_manager->window_destroy(DisplayServer::MAIN_WINDOW_ID); } -- (BOOL)createFramebuffer { - glGenFramebuffersOES(1, &viewFramebuffer); - glGenRenderbuffersOES(1, &viewRenderbuffer); - - glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer); - glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); - // This call associates the storage for the current render buffer with the EAGLDrawable (our CAself) - // allowing us to draw into a buffer that will later be rendered to screen wherever the layer is (which corresponds with our view). - [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(id)self]; - glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer); - - glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth); - glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight); - - // For this sample, we also need a depth buffer, so we'll create and attach one via another renderbuffer. - glGenRenderbuffersOES(1, &depthRenderbuffer); - glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer); - glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight); - glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer); - - if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) { - NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES)); - return NO; - } - - GLES3::TextureStorage::system_fbo = viewFramebuffer; - - return YES; -} - -// Clean up any buffers we have allocated. -- (void)destroyFramebuffer { - GLES3::TextureStorage::system_fbo = 0; - - glDeleteFramebuffersOES(1, &viewFramebuffer); - viewFramebuffer = 0; - glDeleteRenderbuffersOES(1, &viewRenderbuffer); - viewRenderbuffer = 0; - - if (depthRenderbuffer) { - glDeleteRenderbuffersOES(1, &depthRenderbuffer); - depthRenderbuffer = 0; - } +- (void)setupContext:(GLManager *)context withSurface:(Ref *)surface { + gl_manager = context; + native_surface = *surface; + gl_manager->initialize(); + gl_manager->window_create(DisplayServer::MAIN_WINDOW_ID, native_surface, 0, 0); } @end diff --git a/platform/ios/display_server_ios.h b/platform/ios/display_server_ios.h index c8538d29e291..9901a6d031c4 100644 --- a/platform/ios/display_server_ios.h +++ b/platform/ios/display_server_ios.h @@ -32,11 +32,34 @@ #include "drivers/apple_embedded/display_server_apple_embedded.h" +#if defined(RD_ENABLED) +#include "servers/rendering/renderer_rd/renderer_compositor_rd.h" +#include "servers/rendering/rendering_device.h" + +#if defined(VULKAN_ENABLED) + +#include "drivers/vulkan/godot_vulkan.h" +#endif // VULKAN_ENABLED + +#if defined(METAL_ENABLED) +#include "drivers/metal/rendering_context_driver_metal.h" +#endif // METAL_ENABLED +#endif // RD_ENABLED + +#if defined(GLES3_ENABLED) +#include "drivers/gles3/rasterizer_gles3.h" +#endif // GLES3_ENABLED + +#import +#import + class DisplayServerIOS : public DisplayServerAppleEmbedded { GDSOFTCLASS(DisplayServerIOS, DisplayServerAppleEmbedded); _THREAD_SAFE_CLASS_ + void perform_event(const Ref &p_event); + DisplayServerIOS(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error); ~DisplayServerIOS(); diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm index fa42f8b3a2e7..8ab80566d7ce 100644 --- a/platform/ios/display_server_ios.mm +++ b/platform/ios/display_server_ios.mm @@ -31,6 +31,18 @@ #import "display_server_ios.h" #import "device_metrics.h" +#import "display_layer.h" +#import "godot_view.h" +#import "ios.h" +#import "key_mapping_ios.h" +#import "keyboard_input_view.h" +#import "os_ios.h" +#import "tts_ios.h" +#import "view_controller.h" + +#include "core/config/project_settings.h" +#include "core/io/file_access_pack.h" +#include "drivers/apple/rendering_native_surface_apple.h" #import #import diff --git a/platform/ios/libgodot_ios.mm b/platform/ios/libgodot_ios.mm new file mode 100644 index 000000000000..172e819d6553 --- /dev/null +++ b/platform/ios/libgodot_ios.mm @@ -0,0 +1,119 @@ +/**************************************************************************/ +/* libgodot_ios.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 "core/extension/godot_instance.h" +#include "core/extension/libgodot.h" +#include "core/io/libgodot_logger.h" +#include "main/main.h" + +#import "os_ios.h" + +static GodotInstance *instance = nullptr; + +class GodotInstanceCallbacksIOS : public GodotInstanceCallbacks { +public: + void focus_out(GodotInstance *p_instance) override { + OS_IOS::get_singleton()->on_focus_out(); + } + void focus_in(GodotInstance *p_instance) override { + OS_IOS::get_singleton()->on_focus_in(); + } + void pause(GodotInstance *p_instance) override { + p_instance->focus_out(); + } + void resume(GodotInstance *p_instance) override { + p_instance->focus_in(); + } +}; + +static GodotInstanceCallbacksIOS callbacks; + +extern LIBGODOT_API GDExtensionObjectPtr libgodot_create_godot_instance(int p_argc, char *p_argv[], GDExtensionInitializationFunction p_init_func, InvokeCallbackFunction p_async_func, ExecutorData p_async_data, InvokeCallbackFunction p_sync_func, ExecutorData p_sync_data, LogCallbackFunction p_log_func, LogCallbackData p_log_data, void *p_platform_data) { + ERR_FAIL_COND_V_MSG(instance != nullptr, nullptr, "Only one Godot Instance may be created."); + + TaskExecutor *executor = nullptr; + if (p_async_func != nullptr && p_sync_func != nullptr) { + executor = new TaskExecutor(p_async_func, p_async_data, p_sync_func, p_sync_data); + } + + std::function init = [executor, p_argv, p_argc, p_init_func, p_log_func, p_log_data]() { + OS_IOS *os = new OS_IOS(); + if (p_log_func != nullptr && p_log_data != nullptr) { + LibGodotLogger *logger = memnew(LibGodotLogger); + logger->set_callback_function(p_log_func, p_log_data); + os->add_logger(logger); + } + + Error err = Main::setup(p_argv[0], p_argc - 1, &p_argv[1], false); + if (err != OK) { + return; + } + + instance = memnew(GodotInstance); + if (!instance->initialize(p_init_func, &callbacks)) { + memdelete(instance); + instance = nullptr; + os->print("GodotInstance initialization error occurred"); + return; + } + + os->initialize_modules(); + + instance->set_executor(executor); + }; + if (executor != nullptr) { + executor->sync(init); + } else { + init(); + } + + return (GDExtensionObjectPtr)instance; +} + +void libgodot_destroy_godot_instance(GDExtensionObjectPtr p_godot_instance) { + GodotInstance *godot_instance = (GodotInstance *)p_godot_instance; + if (instance == godot_instance) { + const std::function deinit = [godot_instance]() { + godot_instance->stop(); + memdelete(godot_instance); + instance = nullptr; + Main::cleanup(true); + delete OS_IOS::get_singleton(); + }; + + TaskExecutor *executor = instance->get_executor(); + if (executor != nullptr) { + executor->sync(deinit); + delete executor; + } else { + deinit(); + } + } +} diff --git a/platform/ios/os_ios.mm b/platform/ios/os_ios.mm index 6aa35c5404e2..e74c7fe759c7 100644 --- a/platform/ios/os_ios.mm +++ b/platform/ios/os_ios.mm @@ -31,6 +31,7 @@ #import "os_ios.h" #import "display_server_ios.h" +#include "servers/display_server_embedded.h" #ifdef IOS_ENABLED @@ -40,10 +41,15 @@ OS_IOS::OS_IOS() : OS_AppleEmbedded() { +#ifndef LIBGODOT_ENABLED DisplayServerIOS::register_ios_driver(); +#endif + DisplayServerEmbedded::register_embedded_driver(); } -OS_IOS::~OS_IOS() {} +OS_IOS::~OS_IOS() { + AudioDriverManager::reset(); +} String OS_IOS::get_name() const { return "iOS"; diff --git a/platform/linuxbsd/SCsub b/platform/linuxbsd/SCsub index 7de1450bf9d7..5c02600e4638 100644 --- a/platform/linuxbsd/SCsub +++ b/platform/linuxbsd/SCsub @@ -13,6 +13,12 @@ common_linuxbsd = [ "freedesktop_at_spi_monitor.cpp", ] +libgodot_files = [ + "libgodot_linuxbsd.cpp", +] + +executable_files = ["godot_linuxbsd.cpp"] + if env["use_sowrap"]: common_linuxbsd.append("xkbcommon-so_wrap.c") @@ -35,7 +41,12 @@ if env["dbus"]: if env["use_sowrap"]: common_linuxbsd.append("dbus-so_wrap.c") -prog = env.add_program("#bin/godot", ["godot_linuxbsd.cpp"] + common_linuxbsd) +if env["library_type"] == "static_library": + prog = env.add_library("#bin/godot", common_linuxbsd + libgodot_files) +elif env["library_type"] == "shared_library": + prog = env.add_shared_library("#bin/godot", common_linuxbsd + libgodot_files) +else: + prog = env.add_program("#bin/godot", common_linuxbsd + executable_files) if env["debug_symbols"] and env["separate_debug_symbols"]: env.AddPostAction(prog, env.Run(platform_linuxbsd_builders.make_debug_linuxbsd)) diff --git a/platform/linuxbsd/api/api.cpp b/platform/linuxbsd/api/api.cpp new file mode 100644 index 000000000000..ae3c42098c18 --- /dev/null +++ b/platform/linuxbsd/api/api.cpp @@ -0,0 +1,64 @@ +/**************************************************************************/ +/* api.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 "api.h" + +#ifdef LINUXBSD_ENABLED +#include "core/object/class_db.h" + +#ifdef WAYLAND_ENABLED +#include "platform/linuxbsd/wayland/rendering_native_surface_wayland.h" +#endif + +#ifdef X11_ENABLED +#include "platform/linuxbsd/x11/rendering_native_surface_x11.h" +#endif + +#endif + +void register_core_linuxbsd_api() { +#ifdef LINUXBSD_ENABLED +#ifdef WAYLAND_ENABLED + GDREGISTER_ABSTRACT_CLASS(RenderingNativeSurfaceWayland); +#endif +#ifdef X11_ENABLED + GDREGISTER_ABSTRACT_CLASS(RenderingNativeSurfaceX11); +#endif +#endif +} + +void unregister_core_linuxbsd_api() { +} + +void register_linuxbsd_api() { +} + +void unregister_linuxbsd_api() { +} diff --git a/platform/linuxbsd/api/api.h b/platform/linuxbsd/api/api.h new file mode 100644 index 000000000000..ecf86feeed61 --- /dev/null +++ b/platform/linuxbsd/api/api.h @@ -0,0 +1,36 @@ +/**************************************************************************/ +/* api.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. */ +/**************************************************************************/ + +#pragma once + +void register_core_linuxbsd_api(); +void unregister_core_linuxbsd_api(); +void register_linuxbsd_api(); +void unregister_linuxbsd_api(); diff --git a/platform/linuxbsd/libgodot_linuxbsd.cpp b/platform/linuxbsd/libgodot_linuxbsd.cpp new file mode 100644 index 000000000000..06c5a05b3751 --- /dev/null +++ b/platform/linuxbsd/libgodot_linuxbsd.cpp @@ -0,0 +1,70 @@ +/**************************************************************************/ +/* libgodot_linuxbsd.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 "core/extension/libgodot.h" + +#include "core/extension/godot_instance.h" +#include "main/main.h" + +#include "os_linuxbsd.h" + +static OS_LinuxBSD *os = nullptr; + +static GodotInstance *instance = nullptr; + +GDExtensionObjectPtr libgodot_create_godot_instance(int p_argc, char *p_argv[], GDExtensionInitializationFunction p_init_func, InvokeCallbackFunction p_async_func, ExecutorData p_async_data, InvokeCallbackFunction p_sync_func, ExecutorData p_sync_data, LogCallbackFunction p_log_func, LogCallbackData p_log_data, void *p_platform_data) { + ERR_FAIL_COND_V_MSG(instance != nullptr, nullptr, "Only one Godot Instance may be created."); + + os = new OS_LinuxBSD(); + + Error err = Main::setup(p_argv[0], p_argc - 1, &p_argv[1], false); + if (err != OK) { + return nullptr; + } + + instance = memnew(GodotInstance); + if (!instance->initialize(p_init_func)) { + memdelete(instance); + instance = nullptr; + return nullptr; + } + + return (GDExtensionObjectPtr)instance; +} + +void libgodot_destroy_godot_instance(GDExtensionObjectPtr p_godot_instance) { + GodotInstance *godot_instance = (GodotInstance *)p_godot_instance; + if (instance == godot_instance) { + godot_instance->stop(); + memdelete(godot_instance); + instance = nullptr; + Main::cleanup(); + } +} diff --git a/platform/linuxbsd/wayland/SCsub b/platform/linuxbsd/wayland/SCsub index bf05cbc0405b..f94e1ed1a539 100644 --- a/platform/linuxbsd/wayland/SCsub +++ b/platform/linuxbsd/wayland/SCsub @@ -99,6 +99,7 @@ source_files = [ "display_server_wayland.cpp", "key_mapping_xkb.cpp", "wayland_thread.cpp", + "rendering_native_surface_wayland.cpp", ] if env["use_sowrap"]: diff --git a/platform/linuxbsd/wayland/display_server_wayland.cpp b/platform/linuxbsd/wayland/display_server_wayland.cpp index c7d12ffaf333..6ce2b42977e4 100644 --- a/platform/linuxbsd/wayland/display_server_wayland.cpp +++ b/platform/linuxbsd/wayland/display_server_wayland.cpp @@ -39,6 +39,7 @@ #define DEBUG_LOG_WAYLAND(...) #endif +#include "rendering_native_surface_wayland.h" #include "servers/rendering/dummy/rasterizer_dummy.h" #ifdef VULKAN_ENABLED @@ -1937,9 +1938,16 @@ DisplayServerWayland::DisplayServerWayland(const String &p_rendering_driver, Win } #ifdef RD_ENABLED + Ref wayland_surface; #ifdef VULKAN_ENABLED if (rendering_driver == "vulkan") { - rendering_context = memnew(RenderingContextDriverVulkanWayland); + wayland_surface = RenderingNativeSurfaceWayland::create( + wayland_thread.get_wl_display(), + nullptr); + } + + if (wayland_surface.is_valid()) { + rendering_context = wayland_surface->create_rendering_context(rendering_driver); } #endif // VULKAN_ENABLED diff --git a/platform/linuxbsd/wayland/rendering_context_driver_vulkan_wayland.cpp b/platform/linuxbsd/wayland/rendering_context_driver_vulkan_wayland.cpp index 8abcc464baa2..c2a99c01a490 100644 --- a/platform/linuxbsd/wayland/rendering_context_driver_vulkan_wayland.cpp +++ b/platform/linuxbsd/wayland/rendering_context_driver_vulkan_wayland.cpp @@ -31,6 +31,8 @@ #ifdef VULKAN_ENABLED #include "rendering_context_driver_vulkan_wayland.h" +#include "drivers/vulkan/rendering_native_surface_vulkan.h" +#include "rendering_native_surface_wayland.h" #include "drivers/vulkan/godot_vulkan.h" @@ -38,21 +40,22 @@ const char *RenderingContextDriverVulkanWayland::_get_platform_surface_extension return VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME; } -RenderingContextDriver::SurfaceID RenderingContextDriverVulkanWayland::surface_create(const void *p_platform_data) { - const WindowPlatformData *wpd = (const WindowPlatformData *)(p_platform_data); +RenderingContextDriver::SurfaceID RenderingContextDriverVulkanWayland::surface_create(Ref p_native_surface) { + Ref wayland_native_surface = Object::cast_to(*p_native_surface); + ERR_FAIL_COND_V(wayland_native_surface.is_null(), SurfaceID()); VkWaylandSurfaceCreateInfoKHR create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; - create_info.display = wpd->display; - create_info.surface = wpd->surface; + create_info.display = wayland_native_surface->get_display(); + create_info.surface = wayland_native_surface->get_surface(); VkSurfaceKHR vk_surface = VK_NULL_HANDLE; VkResult err = vkCreateWaylandSurfaceKHR(instance_get(), &create_info, get_allocation_callbacks(VK_OBJECT_TYPE_SURFACE_KHR), &vk_surface); ERR_FAIL_COND_V(err != VK_SUCCESS, SurfaceID()); - Surface *surface = memnew(Surface); - surface->vk_surface = vk_surface; - return SurfaceID(surface); + Ref vulkan_surface = RenderingNativeSurfaceVulkan::create(vk_surface); + RenderingContextDriver::SurfaceID result = RenderingContextDriverVulkan::surface_create(vulkan_surface); + return result; } RenderingContextDriverVulkanWayland::RenderingContextDriverVulkanWayland() { diff --git a/platform/linuxbsd/wayland/rendering_context_driver_vulkan_wayland.h b/platform/linuxbsd/wayland/rendering_context_driver_vulkan_wayland.h index 0515471eb92e..6ec7ee73594a 100644 --- a/platform/linuxbsd/wayland/rendering_context_driver_vulkan_wayland.h +++ b/platform/linuxbsd/wayland/rendering_context_driver_vulkan_wayland.h @@ -39,14 +39,9 @@ class RenderingContextDriverVulkanWayland : public RenderingContextDriverVulkan virtual const char *_get_platform_surface_extension() const override final; protected: - SurfaceID surface_create(const void *p_platform_data) override final; + SurfaceID surface_create(Ref p_native_surface) override final; public: - struct WindowPlatformData { - struct wl_display *display; - struct wl_surface *surface; - }; - RenderingContextDriverVulkanWayland(); ~RenderingContextDriverVulkanWayland(); }; diff --git a/platform/linuxbsd/wayland/rendering_native_surface_wayland.cpp b/platform/linuxbsd/wayland/rendering_native_surface_wayland.cpp new file mode 100644 index 000000000000..9e1486df8ec0 --- /dev/null +++ b/platform/linuxbsd/wayland/rendering_native_surface_wayland.cpp @@ -0,0 +1,68 @@ +/**************************************************************************/ +/* rendering_native_surface_wayland.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_native_surface_wayland.h" +#include "core/object/class_db.h" + +#ifdef VULKAN_ENABLED +#include "wayland/rendering_context_driver_vulkan_wayland.h" +#endif + +void RenderingNativeSurfaceWayland::_bind_methods() { + ClassDB::bind_static_method("RenderingNativeSurfaceWayland", D_METHOD("create", "window", "display"), &RenderingNativeSurfaceWayland::create_api); +} + +Ref RenderingNativeSurfaceWayland::create_api(GDExtensionConstPtr p_display, GDExtensionConstPtr p_surface) { + return RenderingNativeSurfaceWayland::create((struct wl_display *)p_display.operator const void *(), (struct wl_surface *)p_surface.operator const void *()); +} + +Ref RenderingNativeSurfaceWayland::create(struct wl_display *p_display, struct wl_surface *p_surface) { + Ref result = memnew(RenderingNativeSurfaceWayland); + result->surface = p_surface; + result->display = p_display; + return result; +} + +RenderingContextDriver *RenderingNativeSurfaceWayland::create_rendering_context(const String &p_driver_name) { +#if defined(VULKAN_ENABLED) + if (p_driver_name == "vulkan") { + return memnew(RenderingContextDriverVulkanWayland); + } +#endif + return nullptr; +} + +RenderingNativeSurfaceWayland::RenderingNativeSurfaceWayland() { + // Does nothing. +} + +RenderingNativeSurfaceWayland::~RenderingNativeSurfaceWayland() { + // Does nothing. +} diff --git a/platform/linuxbsd/wayland/rendering_native_surface_wayland.h b/platform/linuxbsd/wayland/rendering_native_surface_wayland.h new file mode 100644 index 000000000000..b45c8da74d04 --- /dev/null +++ b/platform/linuxbsd/wayland/rendering_native_surface_wayland.h @@ -0,0 +1,61 @@ +/**************************************************************************/ +/* rendering_native_surface_wayland.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. */ +/**************************************************************************/ + +#pragma once + +#include "core/variant/native_ptr.h" +#include "servers/rendering/rendering_native_surface.h" + +class RenderingNativeSurfaceWayland : public RenderingNativeSurface { + GDCLASS(RenderingNativeSurfaceWayland, RenderingNativeSurface); + + static void _bind_methods(); + + struct wl_display *display; + struct wl_surface *surface; + +public: + static Ref create_api(GDExtensionConstPtr p_display, GDExtensionConstPtr p_surface); + + static Ref create(struct wl_display *p_display, wl_surface *p_surface); + + struct wl_display *get_display() const { + return display; + } + + struct wl_surface *get_surface() const { + return surface; + } + + RenderingContextDriver *create_rendering_context(const String &p_driver_name) override; + + RenderingNativeSurfaceWayland(); + ~RenderingNativeSurfaceWayland(); +}; diff --git a/platform/linuxbsd/x11/SCsub b/platform/linuxbsd/x11/SCsub index b76b98447f92..0d2cbb29e3c4 100644 --- a/platform/linuxbsd/x11/SCsub +++ b/platform/linuxbsd/x11/SCsub @@ -6,6 +6,7 @@ Import("env") source_files = [ "display_server_x11.cpp", "key_mapping_x11.cpp", + "rendering_native_surface_x11.cpp", ] if env["use_sowrap"]: diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index fd90c8b055d0..c7b4ba0c8b7d 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -43,6 +43,7 @@ #include "drivers/png/png_driver_common.h" #include "main/main.h" +#include "rendering_native_surface_x11.h" #include "servers/rendering/dummy/rasterizer_dummy.h" #if defined(VULKAN_ENABLED) @@ -6596,19 +6597,29 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V _update_size_hints(id); #if defined(RD_ENABLED) - if (rendering_context) { - union { + Ref x11_surface = nullptr; #ifdef VULKAN_ENABLED - RenderingContextDriverVulkanX11::WindowPlatformData vulkan; + if (rendering_driver == "vulkan") { + x11_surface = RenderingNativeSurfaceX11::create(wd.x11_window, x11_display); + } #endif - } wpd; -#ifdef VULKAN_ENABLED - if (rendering_driver == "vulkan") { - wpd.vulkan.window = wd.x11_window; - wpd.vulkan.display = x11_display; + + if (!rendering_context) { + if (x11_surface.is_valid()) { + rendering_context = x11_surface->create_rendering_context(rendering_driver); } -#endif - Error err = rendering_context->window_create(id, &wpd); + + if (rendering_context) { + if (rendering_context->initialize() != OK) { + memdelete(rendering_context); + rendering_context = nullptr; + ERR_FAIL_V_MSG(INVALID_WINDOW_ID, vformat("Could not initialize %s", rendering_driver)); + } + } + } + + if (rendering_context) { + Error err = rendering_context->window_create(id, x11_surface); ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, vformat("Can't create a %s window", rendering_driver)); rendering_context->window_set_size(id, win_rect.size.width, win_rect.size.height); @@ -7041,46 +7052,13 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode } #if defined(RD_ENABLED) -#if defined(VULKAN_ENABLED) +#ifdef VULKAN_ENABLED if (rendering_driver == "vulkan") { - rendering_context = memnew(RenderingContextDriverVulkanX11); - } -#endif // VULKAN_ENABLED - - if (rendering_context) { - if (rendering_context->initialize() != OK) { - memdelete(rendering_context); - rendering_context = nullptr; -#if defined(GLES3_ENABLED) - bool fallback_to_opengl3 = GLOBAL_GET("rendering/rendering_device/fallback_to_opengl3"); - if (fallback_to_opengl3 && rendering_driver != "opengl3") { - WARN_PRINT("Your video card drivers seem not to support the required Vulkan version, switching to OpenGL 3."); - rendering_driver = "opengl3"; - OS::get_singleton()->set_current_rendering_method("gl_compatibility"); - OS::get_singleton()->set_current_rendering_driver_name(rendering_driver); - } else -#endif // GLES3_ENABLED - { - r_error = ERR_CANT_CREATE; - - if (p_rendering_driver == "vulkan") { - OS::get_singleton()->alert( - vformat("Your video card drivers seem not to support the required Vulkan version.\n\n" - "If possible, consider updating your video card drivers or using the OpenGL 3 driver.\n\n" - "You can enable the OpenGL 3 driver by starting the engine from the\n" - "command line with the command:\n\n \"%s\" --rendering-driver opengl3\n\n" - "If you recently updated your video card drivers, try rebooting.", - executable_name), - "Unable to initialize Vulkan video driver"); - } - - ERR_FAIL_MSG(vformat("Could not initialize %s", rendering_driver)); - } - } driver_found = true; } -#endif // RD_ENABLED - +#endif +#endif + // Initialize context and rendering device. #if defined(GLES3_ENABLED) if (rendering_driver == "opengl3" || rendering_driver == "opengl3_es") { if (getenv("DRI_PRIME") == nullptr) { diff --git a/platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.cpp b/platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.cpp index cbcf07852bad..4a8a43a379d8 100644 --- a/platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.cpp +++ b/platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.cpp @@ -31,6 +31,8 @@ #ifdef VULKAN_ENABLED #include "rendering_context_driver_vulkan_x11.h" +#include "drivers/vulkan/rendering_native_surface_vulkan.h" +#include "rendering_native_surface_x11.h" #include "drivers/vulkan/godot_vulkan.h" @@ -38,21 +40,22 @@ const char *RenderingContextDriverVulkanX11::_get_platform_surface_extension() c return VK_KHR_XLIB_SURFACE_EXTENSION_NAME; } -RenderingContextDriver::SurfaceID RenderingContextDriverVulkanX11::surface_create(const void *p_platform_data) { - const WindowPlatformData *wpd = (const WindowPlatformData *)(p_platform_data); +RenderingContextDriver::SurfaceID RenderingContextDriverVulkanX11::surface_create(Ref p_native_surface) { + Ref x11_native_surface = Object::cast_to(*p_native_surface); + ERR_FAIL_COND_V(x11_native_surface.is_null(), SurfaceID()); VkXlibSurfaceCreateInfoKHR create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; - create_info.dpy = wpd->display; - create_info.window = wpd->window; + create_info.dpy = x11_native_surface->get_display(); + create_info.window = x11_native_surface->get_window(); VkSurfaceKHR vk_surface = VK_NULL_HANDLE; VkResult err = vkCreateXlibSurfaceKHR(instance_get(), &create_info, get_allocation_callbacks(VK_OBJECT_TYPE_SURFACE_KHR), &vk_surface); ERR_FAIL_COND_V(err != VK_SUCCESS, SurfaceID()); - Surface *surface = memnew(Surface); - surface->vk_surface = vk_surface; - return SurfaceID(surface); + Ref vulkan_surface = RenderingNativeSurfaceVulkan::create(vk_surface); + RenderingContextDriver::SurfaceID result = RenderingContextDriverVulkan::surface_create(vulkan_surface); + return result; } RenderingContextDriverVulkanX11::RenderingContextDriverVulkanX11() { diff --git a/platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.h b/platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.h index e9dfd96fe7d9..80c2978084eb 100644 --- a/platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.h +++ b/platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.h @@ -34,21 +34,14 @@ #include "drivers/vulkan/rendering_context_driver_vulkan.h" -#include - class RenderingContextDriverVulkanX11 : public RenderingContextDriverVulkan { private: virtual const char *_get_platform_surface_extension() const override final; protected: - SurfaceID surface_create(const void *p_platform_data) override final; + SurfaceID surface_create(Ref p_native_surface) override final; public: - struct WindowPlatformData { - ::Window window; - Display *display; - }; - RenderingContextDriverVulkanX11(); ~RenderingContextDriverVulkanX11(); }; diff --git a/platform/linuxbsd/x11/rendering_native_surface_x11.cpp b/platform/linuxbsd/x11/rendering_native_surface_x11.cpp new file mode 100644 index 000000000000..d00a745b56aa --- /dev/null +++ b/platform/linuxbsd/x11/rendering_native_surface_x11.cpp @@ -0,0 +1,68 @@ +/**************************************************************************/ +/* rendering_native_surface_x11.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_native_surface_x11.h" +#include "core/object/class_db.h" + +#if defined(VULKAN_ENABLED) +#include "x11/rendering_context_driver_vulkan_x11.h" +#endif + +void RenderingNativeSurfaceX11::_bind_methods() { + ClassDB::bind_static_method("RenderingNativeSurfaceX11", D_METHOD("create", "window", "display"), &RenderingNativeSurfaceX11::create_api); +} + +Ref RenderingNativeSurfaceX11::create_api(GDExtensionConstPtr p_window, GDExtensionConstPtr p_display) { + return RenderingNativeSurfaceX11::create((::Window)p_window.operator const void *(), (Display *)p_display.operator const void *()); +} + +Ref RenderingNativeSurfaceX11::create(::Window p_window, Display *p_display) { + Ref result = memnew(RenderingNativeSurfaceX11); + result->window = p_window; + result->display = p_display; + return result; +} + +RenderingContextDriver *RenderingNativeSurfaceX11::create_rendering_context(const String &p_driver_name) { +#if defined(VULKAN_ENABLED) + if (p_driver_name == "vulkan") { + return memnew(RenderingContextDriverVulkanX11); + } +#endif + return nullptr; +} + +RenderingNativeSurfaceX11::RenderingNativeSurfaceX11() { + // Does nothing. +} + +RenderingNativeSurfaceX11::~RenderingNativeSurfaceX11() { + // Does nothing. +} diff --git a/platform/linuxbsd/x11/rendering_native_surface_x11.h b/platform/linuxbsd/x11/rendering_native_surface_x11.h new file mode 100644 index 000000000000..f11644715c56 --- /dev/null +++ b/platform/linuxbsd/x11/rendering_native_surface_x11.h @@ -0,0 +1,63 @@ +/**************************************************************************/ +/* rendering_native_surface_x11.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. */ +/**************************************************************************/ + +#pragma once + +#include "core/variant/native_ptr.h" +#include "servers/rendering/rendering_native_surface.h" + +#include + +class RenderingNativeSurfaceX11 : public RenderingNativeSurface { + GDCLASS(RenderingNativeSurfaceX11, RenderingNativeSurface); + + static void _bind_methods(); + + ::Window window; + Display *display; + +public: + static Ref create_api(GDExtensionConstPtr p_window, GDExtensionConstPtr p_display); + + static Ref create(::Window p_window, Display *p_display); + + ::Window get_window() const { + return window; + } + + Display *get_display() const { + return display; + } + + RenderingContextDriver *create_rendering_context(const String &p_driver_name) override; + + RenderingNativeSurfaceX11(); + ~RenderingNativeSurfaceX11(); +}; diff --git a/platform/macos/SCsub b/platform/macos/SCsub index 19b0acb74f3e..dbc99c4afeba 100644 --- a/platform/macos/SCsub +++ b/platform/macos/SCsub @@ -5,13 +5,13 @@ import platform_macos_builders Import("env") -files = [ +common_files = [ "os_macos.mm", "godot_application.mm", "godot_application_delegate.mm", "crash_handler_macos.mm", "display_server_macos_base.mm", - "display_server_embedded.mm", + "display_server_macos_embedded.mm", "display_server_macos.mm", "embedded_debugger.mm", "embedded_gl_manager.mm", @@ -21,25 +21,36 @@ files = [ "godot_window_delegate.mm", "godot_window.mm", "key_mapping_macos.mm", - "godot_main_macos.mm", "godot_menu_delegate.mm", "godot_menu_item.mm", "godot_open_save_delegate.mm", "native_menu_macos.mm", "dir_access_macos.mm", "tts_macos.mm", - "rendering_context_driver_vulkan_macos.mm", "gl_manager_macos_angle.mm", "gl_manager_macos_legacy.mm", ] if env.editor_build: - files += [ + common_files += [ "editor/embedded_game_view_plugin.mm", "editor/embedded_process_macos.mm", ] -prog = env.add_program("#bin/godot", files) +executable_files = [ + "godot_main_macos.mm", +] + +libgodot_files = [ + "libgodot_macos.mm", +] + +if env["library_type"] == "static_library": + prog = env.add_library("#bin/godot", common_files + libgodot_files) +elif env["library_type"] == "shared_library": + prog = env.add_shared_library("#bin/godot", common_files + libgodot_files) +else: + prog = env.add_program("#bin/godot", common_files + executable_files) if env["debug_symbols"] and env["separate_debug_symbols"]: env.AddPostAction(prog, env.Run(platform_macos_builders.make_debug_macos)) diff --git a/platform/macos/api/api.cpp b/platform/macos/api/api.cpp new file mode 100644 index 000000000000..9ce4f3d8153e --- /dev/null +++ b/platform/macos/api/api.cpp @@ -0,0 +1,53 @@ +/**************************************************************************/ +/* api.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 "api.h" + +#ifdef MACOS_ENABLED +#include "core/object/class_db.h" + +#include "drivers/apple/rendering_native_surface_apple.h" + +#endif + +void register_core_macos_api() { +#ifdef MACOS_ENABLED + GDREGISTER_ABSTRACT_CLASS(RenderingNativeSurfaceApple); +#endif +} + +void unregister_core_macos_api() { +} + +void register_macos_api() { +} + +void unregister_macos_api() { +} diff --git a/platform/macos/api/api.h b/platform/macos/api/api.h new file mode 100644 index 000000000000..9440cdc98658 --- /dev/null +++ b/platform/macos/api/api.h @@ -0,0 +1,36 @@ +/**************************************************************************/ +/* api.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. */ +/**************************************************************************/ + +#pragma once + +void register_core_macos_api(); +void unregister_core_macos_api(); +void register_macos_api(); +void unregister_macos_api(); diff --git a/platform/macos/detect.py b/platform/macos/detect.py index 321e22b53142..9873233baaea 100644 --- a/platform/macos/detect.py +++ b/platform/macos/detect.py @@ -172,8 +172,9 @@ def configure(env: "SConsEnvironment"): env.Append(CCFLAGS=["-fsanitize=thread"]) env.Append(LINKFLAGS=["-fsanitize=thread"]) - env.Append(LINKFLAGS=["-Wl,-stack_size," + hex(STACK_SIZE_SANITIZERS)]) - else: + if env["library_type"] == "executable": + env.Append(LINKFLAGS=["-Wl,-stack_size," + hex(STACK_SIZE_SANITIZERS)]) + elif env["library_type"] == "executable": env.Append(LINKFLAGS=["-Wl,-stack_size," + hex(STACK_SIZE)]) if env["use_coverage"]: diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h index a6f4f36c89e1..85b71b0415ea 100644 --- a/platform/macos/display_server_macos.h +++ b/platform/macos/display_server_macos.h @@ -43,7 +43,7 @@ #include "servers/rendering/rendering_device.h" #if defined(VULKAN_ENABLED) -#import "rendering_context_driver_vulkan_macos.h" +#import "drivers/apple/rendering_context_driver_vulkan_apple.h" #endif // VULKAN_ENABLED #if defined(METAL_ENABLED) #import "drivers/metal/rendering_context_driver_metal.h" diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm index 7eac6cdd0e4f..229b3f2170bd 100644 --- a/platform/macos/display_server_macos.mm +++ b/platform/macos/display_server_macos.mm @@ -53,7 +53,7 @@ #include "scene/resources/image_texture.h" #ifdef TOOLS_ENABLED -#import "display_server_embedded.h" +#import "display_server_macos_embedded.h" #import "editor/embedded_process_macos.h" #endif @@ -73,6 +73,8 @@ #include "drivers/accesskit/accessibility_driver_accesskit.h" #endif +#include "drivers/apple/rendering_native_surface_apple.h" + #import #import #import @@ -163,26 +165,28 @@ } #if defined(RD_ENABLED) - if (rendering_context) { - union { -#ifdef VULKAN_ENABLED - RenderingContextDriverVulkanMacOS::WindowPlatformData vulkan; -#endif -#ifdef METAL_ENABLED - RenderingContextDriverMetal::WindowPlatformData metal; -#endif - } wpd; -#ifdef VULKAN_ENABLED - if (rendering_driver == "vulkan") { - wpd.vulkan.layer_ptr = (CAMetalLayer *const *)&layer; + Ref apple_surface; + if (rendering_driver == "vulkan" || rendering_driver == "metal") { + apple_surface = RenderingNativeSurfaceApple::create((__bridge void *)layer); + } + + if (!rendering_context) { + if (apple_surface.is_valid()) { + rendering_context = apple_surface->create_rendering_context(rendering_driver); } -#endif -#ifdef METAL_ENABLED - if (rendering_driver == "metal") { - wpd.metal.layer = (CAMetalLayer *)layer; + + if (rendering_context) { + if (rendering_context->initialize() != OK) { + memdelete(rendering_context); + rendering_context = nullptr; + ERR_PRINT("Could not initialize " + rendering_driver); + return INVALID_WINDOW_ID; + } } -#endif - Error err = rendering_context->window_create(window_id_counter, &wpd); + } + + if (rendering_context) { + Error err = rendering_context->window_create(window_id_counter, apple_surface); #ifdef ACCESSKIT_ENABLED if (err != OK && accessibility_driver) { accessibility_driver->window_destroy(id); @@ -3862,7 +3866,7 @@ } #endif if (rendering_driver == "vulkan") { - rendering_context = memnew(RenderingContextDriverVulkanMacOS); + rendering_context = memnew(RenderingContextDriverVulkanApple); } #endif #if defined(METAL_ENABLED) @@ -3937,7 +3941,10 @@ } WindowID main_window = _create_window(p_mode, p_vsync_mode, Rect2i(window_position, p_resolution)); - ERR_FAIL_COND(main_window == INVALID_WINDOW_ID); + if (main_window == INVALID_WINDOW_ID) { + r_error = ERR_CANT_CREATE; + ERR_FAIL_MSG("Could not create main window."); + } for (int i = 0; i < WINDOW_FLAG_MAX; i++) { if (p_flags & (1 << i)) { window_set_flag(WindowFlags(i), true, main_window); diff --git a/platform/macos/display_server_embedded.h b/platform/macos/display_server_macos_embedded.h similarity index 95% rename from platform/macos/display_server_embedded.h rename to platform/macos/display_server_macos_embedded.h index 39f22f255c26..6c3d56edef98 100644 --- a/platform/macos/display_server_embedded.h +++ b/platform/macos/display_server_macos_embedded.h @@ -1,5 +1,5 @@ /**************************************************************************/ -/* display_server_embedded.h */ +/* display_server_macos_embedded.h */ /**************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -55,8 +55,8 @@ struct DisplayServerEmbeddedState { } }; -class DisplayServerEmbedded : public DisplayServerMacOSBase { - GDSOFTCLASS(DisplayServerEmbedded, DisplayServerMacOSBase) +class DisplayServerMacOSEmbedded : public DisplayServerMacOSBase { + GDSOFTCLASS(DisplayServerMacOSEmbedded, DisplayServerMacOSBase) DisplayServerEmbeddedState state; @@ -221,6 +221,6 @@ class DisplayServerEmbedded : public DisplayServerMacOSBase { void set_state(const DisplayServerEmbeddedState &p_state); virtual void swap_buffers() override; - DisplayServerEmbedded(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, Error &r_error); - ~DisplayServerEmbedded(); + DisplayServerMacOSEmbedded(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, Error &r_error); + ~DisplayServerMacOSEmbedded(); }; diff --git a/platform/macos/display_server_embedded.mm b/platform/macos/display_server_macos_embedded.mm similarity index 71% rename from platform/macos/display_server_embedded.mm rename to platform/macos/display_server_macos_embedded.mm index 916c681dcb99..e32f0aea378b 100644 --- a/platform/macos/display_server_embedded.mm +++ b/platform/macos/display_server_macos_embedded.mm @@ -1,5 +1,5 @@ /**************************************************************************/ -/* display_server_embedded.mm */ +/* display_server_macos_embedded.mm */ /**************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#import "display_server_embedded.h" +#import "display_server_macos_embedded.h" #if defined(GLES3_ENABLED) #import "embedded_gl_manager.h" @@ -42,11 +42,12 @@ #import "servers/rendering/rendering_device.h" #if defined(VULKAN_ENABLED) -#import "rendering_context_driver_vulkan_macos.h" +#import "drivers/apple/rendering_context_driver_vulkan_apple.h" #endif // VULKAN_ENABLED #if defined(METAL_ENABLED) #import "drivers/metal/rendering_context_driver_metal.h" #endif +#include "drivers/apple/rendering_native_surface_apple.h" #endif // RD_ENABLED #import "embedded_debugger.h" @@ -56,7 +57,7 @@ #import "core/debugger/engine_debugger.h" #import "core/io/marshalls.h" -DisplayServerEmbedded::DisplayServerEmbedded(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, Error &r_error) { +DisplayServerMacOSEmbedded::DisplayServerMacOSEmbedded(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, Error &r_error) { EmbeddedDebugger::initialize(this); r_error = OK; // default to OK @@ -81,7 +82,7 @@ } #endif if (rendering_driver == "vulkan") { - rendering_context = memnew(RenderingContextDriverVulkanMacOS); + rendering_context = memnew(RenderingContextDriverVulkanApple); } #endif #if defined(METAL_ENABLED) @@ -144,25 +145,12 @@ layer = [CAMetalLayer new]; layer.anchorPoint = CGPointMake(0, 1); - union { -#ifdef VULKAN_ENABLED - RenderingContextDriverVulkanMacOS::WindowPlatformData vulkan; -#endif -#ifdef METAL_ENABLED - RenderingContextDriverMetal::WindowPlatformData metal; -#endif - } wpd; -#ifdef VULKAN_ENABLED - if (rendering_driver == "vulkan") { - wpd.vulkan.layer_ptr = (CAMetalLayer *const *)&layer; - } -#endif -#ifdef METAL_ENABLED - if (rendering_driver == "metal") { - wpd.metal.layer = (CAMetalLayer *)layer; + Ref apple_surface; + if (rendering_driver == "vulkan" || rendering_driver == "metal") { + apple_surface = RenderingNativeSurfaceApple::create((__bridge void *)layer); } -#endif - Error err = rendering_context->window_create(window_id_counter, &wpd); + + Error err = rendering_context->window_create(window_id_counter, apple_surface); ERR_FAIL_COND_MSG(err != OK, vformat("Can't create a %s context", rendering_driver)); // The rendering context is always in pixels @@ -211,7 +199,7 @@ } } -DisplayServerEmbedded::~DisplayServerEmbedded() { +DisplayServerMacOSEmbedded::~DisplayServerMacOSEmbedded() { if (native_menu) { memdelete(native_menu); native_menu = nullptr; @@ -239,11 +227,11 @@ #endif } -DisplayServer *DisplayServerEmbedded::create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, int64_t /* p_parent_window */, Error &r_error) { - return memnew(DisplayServerEmbedded(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, p_context, r_error)); +DisplayServer *DisplayServerMacOSEmbedded::create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, int64_t /* p_parent_window */, Error &r_error) { + return memnew(DisplayServerMacOSEmbedded(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, p_context, r_error)); } -Vector DisplayServerEmbedded::get_rendering_drivers_func() { +Vector DisplayServerMacOSEmbedded::get_rendering_drivers_func() { Vector drivers; #if defined(VULKAN_ENABLED) @@ -259,17 +247,17 @@ return drivers; } -void DisplayServerEmbedded::register_embedded_driver() { +void DisplayServerMacOSEmbedded::register_embedded_driver() { register_create_function("embedded", create_func, get_rendering_drivers_func); } -void DisplayServerEmbedded::beep() const { +void DisplayServerMacOSEmbedded::beep() const { NSBeep(); } // MARK: - Mouse -void DisplayServerEmbedded::_mouse_update_mode() { +void DisplayServerMacOSEmbedded::_mouse_update_mode() { MouseMode wanted_mouse_mode = mouse_mode_override_enabled ? mouse_mode_override : mouse_mode_base; @@ -283,7 +271,7 @@ mouse_mode = wanted_mouse_mode; } -void DisplayServerEmbedded::mouse_set_mode(MouseMode p_mode) { +void DisplayServerMacOSEmbedded::mouse_set_mode(MouseMode p_mode) { if (p_mode == mouse_mode_base) { return; } @@ -291,11 +279,11 @@ _mouse_update_mode(); } -DisplayServerEmbedded::MouseMode DisplayServerEmbedded::mouse_get_mode() const { +DisplayServerMacOSEmbedded::MouseMode DisplayServerMacOSEmbedded::mouse_get_mode() const { return mouse_mode; } -void DisplayServerEmbedded::mouse_set_mode_override(MouseMode p_mode) { +void DisplayServerMacOSEmbedded::mouse_set_mode_override(MouseMode p_mode) { ERR_FAIL_INDEX(p_mode, MouseMode::MOUSE_MODE_MAX); if (p_mode == mouse_mode_override) { return; @@ -304,11 +292,11 @@ _mouse_update_mode(); } -DisplayServer::MouseMode DisplayServerEmbedded::mouse_get_mode_override() const { +DisplayServer::MouseMode DisplayServerMacOSEmbedded::mouse_get_mode_override() const { return mouse_mode_override; } -void DisplayServerEmbedded::mouse_set_mode_override_enabled(bool p_override_enabled) { +void DisplayServerMacOSEmbedded::mouse_set_mode_override_enabled(bool p_override_enabled) { if (p_override_enabled == mouse_mode_override_enabled) { return; } @@ -316,17 +304,17 @@ _mouse_update_mode(); } -bool DisplayServerEmbedded::mouse_is_mode_override_enabled() const { +bool DisplayServerMacOSEmbedded::mouse_is_mode_override_enabled() const { return mouse_mode_override_enabled; } -void DisplayServerEmbedded::warp_mouse(const Point2i &p_position) { +void DisplayServerMacOSEmbedded::warp_mouse(const Point2i &p_position) { _THREAD_SAFE_METHOD_ Input::get_singleton()->set_mouse_position(p_position); EngineDebugger::get_singleton()->send_message("game_view:warp_mouse", { p_position }); } -Point2i DisplayServerEmbedded::mouse_get_position() const { +Point2i DisplayServerMacOSEmbedded::mouse_get_position() const { _THREAD_SAFE_METHOD_ const NSPoint mouse_pos = [NSEvent mouseLocation]; @@ -346,7 +334,7 @@ return Vector2i(); } -BitField DisplayServerEmbedded::mouse_get_button_state() const { +BitField DisplayServerMacOSEmbedded::mouse_get_button_state() const { BitField last_button_state = MouseButtonMask::NONE; NSUInteger buttons = [NSEvent pressedMouseButtons]; @@ -370,41 +358,41 @@ // MARK: Events -void DisplayServerEmbedded::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerMacOSEmbedded::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) { window_resize_callbacks[p_window] = p_callable; } -void DisplayServerEmbedded::window_set_window_event_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerMacOSEmbedded::window_set_window_event_callback(const Callable &p_callable, WindowID p_window) { window_event_callbacks[p_window] = p_callable; } -void DisplayServerEmbedded::window_set_input_event_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerMacOSEmbedded::window_set_input_event_callback(const Callable &p_callable, WindowID p_window) { input_event_callbacks[p_window] = p_callable; } -void DisplayServerEmbedded::window_set_input_text_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerMacOSEmbedded::window_set_input_text_callback(const Callable &p_callable, WindowID p_window) { input_text_callbacks[p_window] = p_callable; } -void DisplayServerEmbedded::window_set_drop_files_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerMacOSEmbedded::window_set_drop_files_callback(const Callable &p_callable, WindowID p_window) { // Not supported } -void DisplayServerEmbedded::process_events() { +void DisplayServerMacOSEmbedded::process_events() { Input *input = Input::get_singleton(); input->flush_buffered_events(); } -void DisplayServerEmbedded::_dispatch_input_events(const Ref &p_event) { +void DisplayServerMacOSEmbedded::_dispatch_input_events(const Ref &p_event) { Ref event_from_window = p_event; WindowID window_id = INVALID_WINDOW_ID; if (event_from_window.is_valid()) { window_id = event_from_window->get_window_id(); } - DisplayServerEmbedded *ds = (DisplayServerEmbedded *)DisplayServer::get_singleton(); + DisplayServerMacOSEmbedded *ds = (DisplayServerMacOSEmbedded *)DisplayServer::get_singleton(); ds->send_input_event(p_event, window_id); } -void DisplayServerEmbedded::send_input_event(const Ref &p_event, WindowID p_id) const { +void DisplayServerMacOSEmbedded::send_input_event(const Ref &p_event, WindowID p_id) const { if (p_id != INVALID_WINDOW_ID) { const Callable *cb = input_event_callbacks.getptr(p_id); if (cb) { @@ -417,21 +405,21 @@ } } -void DisplayServerEmbedded::send_input_text(const String &p_text, WindowID p_id) const { +void DisplayServerMacOSEmbedded::send_input_text(const String &p_text, WindowID p_id) const { const Callable *cb = input_text_callbacks.getptr(p_id); if (cb) { _window_callback(*cb, p_text); } } -void DisplayServerEmbedded::send_window_event(DisplayServer::WindowEvent p_event, WindowID p_id) const { +void DisplayServerMacOSEmbedded::send_window_event(DisplayServer::WindowEvent p_event, WindowID p_id) const { const Callable *cb = window_event_callbacks.getptr(p_id); if (cb) { _window_callback(*cb, int(p_event)); } } -void DisplayServerEmbedded::_window_callback(const Callable &p_callable, const Variant &p_arg) const { +void DisplayServerMacOSEmbedded::_window_callback(const Callable &p_callable, const Variant &p_arg) const { if (p_callable.is_valid()) { p_callable.call(p_arg); } @@ -439,7 +427,7 @@ // MARK: - -bool DisplayServerEmbedded::has_feature(Feature p_feature) const { +bool DisplayServerMacOSEmbedded::has_feature(Feature p_feature) const { switch (p_feature) { #ifndef DISABLE_DEPRECATED case FEATURE_GLOBAL_MENU: { @@ -468,19 +456,19 @@ } } -String DisplayServerEmbedded::get_name() const { +String DisplayServerMacOSEmbedded::get_name() const { return "embedded"; } -int DisplayServerEmbedded::get_screen_count() const { +int DisplayServerMacOSEmbedded::get_screen_count() const { return 1; } -int DisplayServerEmbedded::get_primary_screen() const { +int DisplayServerMacOSEmbedded::get_primary_screen() const { return 0; } -Point2i DisplayServerEmbedded::screen_get_position(int p_screen) const { +Point2i DisplayServerMacOSEmbedded::screen_get_position(int p_screen) const { _THREAD_SAFE_METHOD_ p_screen = _get_screen_index(p_screen); @@ -490,7 +478,7 @@ return Point2i(0, 0); } -Size2i DisplayServerEmbedded::screen_get_size(int p_screen) const { +Size2i DisplayServerMacOSEmbedded::screen_get_size(int p_screen) const { _THREAD_SAFE_METHOD_ p_screen = _get_screen_index(p_screen); @@ -500,7 +488,7 @@ return window_get_size(MAIN_WINDOW_ID); } -Rect2i DisplayServerEmbedded::screen_get_usable_rect(int p_screen) const { +Rect2i DisplayServerMacOSEmbedded::screen_get_usable_rect(int p_screen) const { _THREAD_SAFE_METHOD_ p_screen = _get_screen_index(p_screen); @@ -510,7 +498,7 @@ return Rect2i(screen_get_position(p_screen), screen_get_size(p_screen)); } -int DisplayServerEmbedded::screen_get_dpi(int p_screen) const { +int DisplayServerMacOSEmbedded::screen_get_dpi(int p_screen) const { _THREAD_SAFE_METHOD_ p_screen = _get_screen_index(p_screen); @@ -520,7 +508,7 @@ return 96; } -float DisplayServerEmbedded::screen_get_scale(int p_screen) const { +float DisplayServerMacOSEmbedded::screen_get_scale(int p_screen) const { _THREAD_SAFE_METHOD_ switch (p_screen) { @@ -535,7 +523,7 @@ } } -float DisplayServerEmbedded::screen_get_refresh_rate(int p_screen) const { +float DisplayServerMacOSEmbedded::screen_get_refresh_rate(int p_screen) const { _THREAD_SAFE_METHOD_ p_screen = _get_screen_index(p_screen); @@ -554,72 +542,72 @@ return SCREEN_REFRESH_RATE_FALLBACK; } -Vector DisplayServerEmbedded::get_window_list() const { +Vector DisplayServerMacOSEmbedded::get_window_list() const { Vector list; list.push_back(MAIN_WINDOW_ID); return list; } -DisplayServer::WindowID DisplayServerEmbedded::get_window_at_screen_position(const Point2i &p_position) const { +DisplayServer::WindowID DisplayServerMacOSEmbedded::get_window_at_screen_position(const Point2i &p_position) const { return MAIN_WINDOW_ID; } -void DisplayServerEmbedded::window_attach_instance_id(ObjectID p_instance, WindowID p_window) { +void DisplayServerMacOSEmbedded::window_attach_instance_id(ObjectID p_instance, WindowID p_window) { window_attached_instance_id[p_window] = p_instance; } -ObjectID DisplayServerEmbedded::window_get_attached_instance_id(WindowID p_window) const { +ObjectID DisplayServerMacOSEmbedded::window_get_attached_instance_id(WindowID p_window) const { return window_attached_instance_id[p_window]; } -void DisplayServerEmbedded::window_set_title(const String &p_title, WindowID p_window) { +void DisplayServerMacOSEmbedded::window_set_title(const String &p_title, WindowID p_window) { // Not supported } -int DisplayServerEmbedded::window_get_current_screen(WindowID p_window) const { +int DisplayServerMacOSEmbedded::window_get_current_screen(WindowID p_window) const { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V(p_window != MAIN_WINDOW_ID, INVALID_SCREEN); return 0; } -void DisplayServerEmbedded::window_set_current_screen(int p_screen, WindowID p_window) { +void DisplayServerMacOSEmbedded::window_set_current_screen(int p_screen, WindowID p_window) { // Not supported } -Point2i DisplayServerEmbedded::window_get_position(WindowID p_window) const { +Point2i DisplayServerMacOSEmbedded::window_get_position(WindowID p_window) const { return Point2i(); } -Point2i DisplayServerEmbedded::window_get_position_with_decorations(WindowID p_window) const { +Point2i DisplayServerMacOSEmbedded::window_get_position_with_decorations(WindowID p_window) const { return Point2i(); } -void DisplayServerEmbedded::window_set_position(const Point2i &p_position, WindowID p_window) { +void DisplayServerMacOSEmbedded::window_set_position(const Point2i &p_position, WindowID p_window) { // Probably not supported for single window iOS app } -void DisplayServerEmbedded::window_set_transient(WindowID p_window, WindowID p_parent) { +void DisplayServerMacOSEmbedded::window_set_transient(WindowID p_window, WindowID p_parent) { // Not supported } -void DisplayServerEmbedded::window_set_max_size(const Size2i p_size, WindowID p_window) { +void DisplayServerMacOSEmbedded::window_set_max_size(const Size2i p_size, WindowID p_window) { // Not supported } -Size2i DisplayServerEmbedded::window_get_max_size(WindowID p_window) const { +Size2i DisplayServerMacOSEmbedded::window_get_max_size(WindowID p_window) const { return Size2i(); } -void DisplayServerEmbedded::window_set_min_size(const Size2i p_size, WindowID p_window) { +void DisplayServerMacOSEmbedded::window_set_min_size(const Size2i p_size, WindowID p_window) { // Not supported } -Size2i DisplayServerEmbedded::window_get_min_size(WindowID p_window) const { +Size2i DisplayServerMacOSEmbedded::window_get_min_size(WindowID p_window) const { return Size2i(); } -void DisplayServerEmbedded::window_set_size(const Size2i p_size, WindowID p_window) { +void DisplayServerMacOSEmbedded::window_set_size(const Size2i p_size, WindowID p_window) { [CATransaction begin]; [CATransaction setDisableActions:YES]; @@ -648,7 +636,7 @@ } } -Size2i DisplayServerEmbedded::window_get_size(WindowID p_window) const { +Size2i DisplayServerMacOSEmbedded::window_get_size(WindowID p_window) const { #if defined(RD_ENABLED) if (rendering_context) { RenderingContextDriver::SurfaceID surface = rendering_context->surface_get_from_window(p_window); @@ -666,65 +654,65 @@ return Size2i(); } -Size2i DisplayServerEmbedded::window_get_size_with_decorations(WindowID p_window) const { +Size2i DisplayServerMacOSEmbedded::window_get_size_with_decorations(WindowID p_window) const { return window_get_size(p_window); } -void DisplayServerEmbedded::window_set_mode(WindowMode p_mode, WindowID p_window) { +void DisplayServerMacOSEmbedded::window_set_mode(WindowMode p_mode, WindowID p_window) { // Not supported } -DisplayServer::WindowMode DisplayServerEmbedded::window_get_mode(WindowID p_window) const { +DisplayServer::WindowMode DisplayServerMacOSEmbedded::window_get_mode(WindowID p_window) const { return WindowMode::WINDOW_MODE_WINDOWED; } -bool DisplayServerEmbedded::window_is_maximize_allowed(WindowID p_window) const { +bool DisplayServerMacOSEmbedded::window_is_maximize_allowed(WindowID p_window) const { return false; } -void DisplayServerEmbedded::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) { +void DisplayServerMacOSEmbedded::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) { if (p_flag == WINDOW_FLAG_TRANSPARENT && p_window == MAIN_WINDOW_ID) { transparent = p_enabled; layer.opaque = !(OS::get_singleton()->is_layered_allowed() && transparent); } } -bool DisplayServerEmbedded::window_get_flag(WindowFlags p_flag, WindowID p_window) const { +bool DisplayServerMacOSEmbedded::window_get_flag(WindowFlags p_flag, WindowID p_window) const { if (p_flag == WINDOW_FLAG_TRANSPARENT && p_window == MAIN_WINDOW_ID) { return transparent; } return false; } -void DisplayServerEmbedded::window_request_attention(WindowID p_window) { +void DisplayServerMacOSEmbedded::window_request_attention(WindowID p_window) { // Not supported } -void DisplayServerEmbedded::window_move_to_foreground(WindowID p_window) { +void DisplayServerMacOSEmbedded::window_move_to_foreground(WindowID p_window) { // Not supported } -bool DisplayServerEmbedded::window_is_focused(WindowID p_window) const { +bool DisplayServerMacOSEmbedded::window_is_focused(WindowID p_window) const { return true; } -float DisplayServerEmbedded::screen_get_max_scale() const { +float DisplayServerMacOSEmbedded::screen_get_max_scale() const { return state.screen_max_scale; } -bool DisplayServerEmbedded::window_can_draw(WindowID p_window) const { +bool DisplayServerMacOSEmbedded::window_can_draw(WindowID p_window) const { return true; } -bool DisplayServerEmbedded::can_any_window_draw() const { +bool DisplayServerMacOSEmbedded::can_any_window_draw() const { return true; } -void DisplayServerEmbedded::window_set_ime_active(const bool p_active, WindowID p_window) { +void DisplayServerMacOSEmbedded::window_set_ime_active(const bool p_active, WindowID p_window) { EngineDebugger::get_singleton()->send_message("game_view:window_set_ime_active", { p_active }); } -void DisplayServerEmbedded::window_set_ime_position(const Point2i &p_pos, WindowID p_window) { +void DisplayServerMacOSEmbedded::window_set_ime_position(const Point2i &p_pos, WindowID p_window) { if (p_pos == ime_last_position) { return; } @@ -732,7 +720,7 @@ ime_last_position = p_pos; } -void DisplayServerEmbedded::set_state(const DisplayServerEmbeddedState &p_state) { +void DisplayServerMacOSEmbedded::set_state(const DisplayServerEmbeddedState &p_state) { if (state == p_state) { return; } @@ -750,7 +738,7 @@ } } -void DisplayServerEmbedded::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) { +void DisplayServerMacOSEmbedded::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) { #if defined(GLES3_ENABLED) if (gl_manager) { gl_manager->set_vsync_enabled(p_vsync_mode != DisplayServer::VSYNC_DISABLED); @@ -764,7 +752,7 @@ #endif } -DisplayServer::VSyncMode DisplayServerEmbedded::window_get_vsync_mode(WindowID p_window) const { +DisplayServer::VSyncMode DisplayServerMacOSEmbedded::window_get_vsync_mode(WindowID p_window) const { _THREAD_SAFE_METHOD_ #if defined(GLES3_ENABLED) if (gl_manager) { @@ -779,31 +767,31 @@ return DisplayServer::VSYNC_ENABLED; } -void DisplayServerEmbedded::update_im_text(const Point2i &p_selection, const String &p_text) { +void DisplayServerMacOSEmbedded::update_im_text(const Point2i &p_selection, const String &p_text) { im_selection = p_selection; im_text = p_text; OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_OS_IME_UPDATE); } -Point2i DisplayServerEmbedded::ime_get_selection() const { +Point2i DisplayServerMacOSEmbedded::ime_get_selection() const { return im_selection; } -String DisplayServerEmbedded::ime_get_text() const { +String DisplayServerMacOSEmbedded::ime_get_text() const { return im_text; } -void DisplayServerEmbedded::cursor_set_shape(CursorShape p_shape) { +void DisplayServerMacOSEmbedded::cursor_set_shape(CursorShape p_shape) { cursor_shape = p_shape; EngineDebugger::get_singleton()->send_message("game_view:cursor_set_shape", { p_shape }); } -DisplayServer::CursorShape DisplayServerEmbedded::cursor_get_shape() const { +DisplayServer::CursorShape DisplayServerMacOSEmbedded::cursor_get_shape() const { return cursor_shape; } -void DisplayServerEmbedded::cursor_set_custom_image(const Ref &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { +void DisplayServerMacOSEmbedded::cursor_set_custom_image(const Ref &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { PackedByteArray data; if (p_cursor.is_valid()) { Ref image = _get_cursor_image_from_resource(p_cursor, p_hotspot); @@ -814,7 +802,7 @@ EngineDebugger::get_singleton()->send_message("game_view:cursor_set_custom_image", { data, p_shape, p_hotspot }); } -void DisplayServerEmbedded::swap_buffers() { +void DisplayServerMacOSEmbedded::swap_buffers() { #ifdef GLES3_ENABLED if (gl_manager) { gl_manager->swap_buffers(); diff --git a/platform/macos/editor/embedded_process_macos.mm b/platform/macos/editor/embedded_process_macos.mm index 7cd4fb13603a..e3344b0a877a 100644 --- a/platform/macos/editor/embedded_process_macos.mm +++ b/platform/macos/editor/embedded_process_macos.mm @@ -30,8 +30,8 @@ #include "embedded_process_macos.h" -#include "platform/macos/display_server_embedded.h" #include "platform/macos/display_server_macos.h" +#include "platform/macos/display_server_macos_embedded.h" #include "core/input/input_event_codec.h" #include "editor/debugger/script_editor_debugger.h" diff --git a/platform/macos/embedded_debugger.h b/platform/macos/embedded_debugger.h index 74217b2f20ec..37f06c2e1619 100644 --- a/platform/macos/embedded_debugger.h +++ b/platform/macos/embedded_debugger.h @@ -33,23 +33,23 @@ #include "core/templates/hash_map.h" #include "core/variant/array.h" -class DisplayServerEmbedded; +class DisplayServerMacOSEmbedded; /// @brief Singleton class to process embedded debugging message in the child process. class EmbeddedDebugger { inline static EmbeddedDebugger *singleton = nullptr; - EmbeddedDebugger(DisplayServerEmbedded *p_ds); + EmbeddedDebugger(DisplayServerMacOSEmbedded *p_ds); public: - static void initialize(DisplayServerEmbedded *p_ds); + static void initialize(DisplayServerMacOSEmbedded *p_ds); static void deinitialize(); ~EmbeddedDebugger(); #ifdef DEBUG_ENABLED private: - DisplayServerEmbedded *ds; + DisplayServerMacOSEmbedded *ds; /// Message handler function for parse_message. typedef Error (EmbeddedDebugger::*ParseMessageFunc)(const Array &p_args); diff --git a/platform/macos/embedded_debugger.mm b/platform/macos/embedded_debugger.mm index d89f8981d677..035ba23c6e41 100644 --- a/platform/macos/embedded_debugger.mm +++ b/platform/macos/embedded_debugger.mm @@ -30,7 +30,7 @@ #include "embedded_debugger.h" -#include "display_server_embedded.h" +#include "display_server_macos_embedded.h" #include "core/debugger/engine_debugger.h" #include "core/input/input_event_codec.h" @@ -39,7 +39,7 @@ HashMap EmbeddedDebugger::parse_message_handlers; #endif -EmbeddedDebugger::EmbeddedDebugger(DisplayServerEmbedded *p_ds) { +EmbeddedDebugger::EmbeddedDebugger(DisplayServerMacOSEmbedded *p_ds) { singleton = this; #ifdef DEBUG_ENABLED @@ -55,7 +55,7 @@ singleton = nullptr; } -void EmbeddedDebugger::initialize(DisplayServerEmbedded *p_ds) { +void EmbeddedDebugger::initialize(DisplayServerMacOSEmbedded *p_ds) { if (EngineDebugger::is_active()) { memnew(EmbeddedDebugger(p_ds)); } diff --git a/platform/macos/embedded_gl_manager.h b/platform/macos/embedded_gl_manager.h index c6fae224844f..b674bb55f2ac 100644 --- a/platform/macos/embedded_gl_manager.h +++ b/platform/macos/embedded_gl_manager.h @@ -108,6 +108,8 @@ class GLManagerEmbedded { void set_vsync_enabled(bool p_enabled); bool is_vsync_enabled() const { return vsync_enabled; } + uint64_t get_fbo(DisplayServer::WindowID p_window_id) const; + void release_current(); void swap_buffers(); diff --git a/platform/macos/embedded_gl_manager.mm b/platform/macos/embedded_gl_manager.mm index 8788bfabf081..2023fca5f820 100644 --- a/platform/macos/embedded_gl_manager.mm +++ b/platform/macos/embedded_gl_manager.mm @@ -148,13 +148,11 @@ glBindTexture(GL_TEXTURE_RECTANGLE, 0); } win.current_fb = 0; - GLES3::TextureStorage::system_fbo = win.framebuffers[win.current_fb].fbo; win.is_valid = true; } void GLManagerEmbedded::GLWindow::destroy_framebuffers() { is_valid = false; - GLES3::TextureStorage::system_fbo = 0; for (FrameBuffer &fb : framebuffers) { if (fb.fbo) { @@ -246,7 +244,6 @@ win.layer.contents = (__bridge id)win.framebuffers[win.current_fb].surface; [CATransaction commit]; win.current_fb = (win.current_fb + 1) % BUFFER_COUNT; - GLES3::TextureStorage::system_fbo = win.framebuffers[win.current_fb].fbo; } Error GLManagerEmbedded::initialize() { @@ -307,6 +304,20 @@ } } +uint64_t GLManagerEmbedded::get_fbo(DisplayServer::WindowID p_window_id) const { + if (current_window == p_window_id) { + return 0; + } + + const GLWindowElement *el = windows.find(p_window_id); + if (el == nullptr) { + return 0; + } + + const GLWindow &win = el->value(); + return win.framebuffers[win.current_fb].fbo; +} + GLManagerEmbedded::GLManagerEmbedded() { display_semaphore = dispatch_semaphore_create(BUFFER_COUNT); diff --git a/platform/macos/gl_manager_macos_angle.h b/platform/macos/gl_manager_macos_angle.h index 4498ef02a6e6..5c454e14916d 100644 --- a/platform/macos/gl_manager_macos_angle.h +++ b/platform/macos/gl_manager_macos_angle.h @@ -57,7 +57,7 @@ class GLManagerANGLE_MacOS : public EGLManager { virtual Vector _get_platform_context_attribs() const override; public: - void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) {} + virtual void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) override {} GLManagerANGLE_MacOS() {} ~GLManagerANGLE_MacOS() {} diff --git a/platform/macos/libgodot_macos.mm b/platform/macos/libgodot_macos.mm new file mode 100644 index 000000000000..4c6210ad95dc --- /dev/null +++ b/platform/macos/libgodot_macos.mm @@ -0,0 +1,73 @@ +/**************************************************************************/ +/* libgodot_macos.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 "core/extension/libgodot.h" + +#include "core/extension/godot_instance.h" +#include "main/main.h" + +#include "os_macos.h" + +static OS_MacOS *os = nullptr; + +static GodotInstance *instance = nullptr; + +GDExtensionObjectPtr libgodot_create_godot_instance(int p_argc, char *p_argv[], GDExtensionInitializationFunction p_init_func, InvokeCallbackFunction p_async_func, ExecutorData p_async_data, InvokeCallbackFunction p_sync_func, ExecutorData p_sync_data, LogCallbackFunction p_log_func, LogCallbackData p_log_data, void *p_platform_data) { + ERR_FAIL_COND_V_MSG(instance != nullptr, nullptr, "Only one Godot Instance may be created."); + + uint32_t remaining_args = p_argc - 1; + os = new OS_MacOS_NSApp(p_argv[0], remaining_args, remaining_args > 0 ? &p_argv[1] : nullptr); + + @autoreleasepool { + Error err = Main::setup(p_argv[0], remaining_args, remaining_args > 0 ? &p_argv[1] : nullptr, false); + if (err != OK) { + return nullptr; + } + + instance = memnew(GodotInstance); + if (!instance->initialize(p_init_func)) { + memdelete(instance); + instance = nullptr; + return nullptr; + } + + return (GDExtensionObjectPtr)instance; + } +} + +void libgodot_destroy_godot_instance(GDExtensionObjectPtr p_godot_instance) { + GodotInstance *godot_instance = (GodotInstance *)p_godot_instance; + if (instance == godot_instance) { + godot_instance->stop(); + memdelete(godot_instance); + instance = nullptr; + Main::cleanup(); + } +} diff --git a/platform/macos/os_macos.mm b/platform/macos/os_macos.mm index 0909329bac52..cb83f2ad4131 100644 --- a/platform/macos/os_macos.mm +++ b/platform/macos/os_macos.mm @@ -32,7 +32,7 @@ #import "dir_access_macos.h" #ifdef DEBUG_ENABLED -#import "display_server_embedded.h" +#import "display_server_macos_embedded.h" #endif #import "display_server_macos.h" #import "godot_application.h" @@ -1248,9 +1248,9 @@ static void handle_interrupt(int sig) { ret = Main::start(); } - DisplayServerEmbedded *ds = Object::cast_to(DisplayServer::get_singleton()); + DisplayServerMacOSEmbedded *ds = Object::cast_to(DisplayServer::get_singleton()); if (!ds) { - ERR_FAIL_MSG("DisplayServerEmbedded is not initialized."); + ERR_FAIL_MSG("DisplayServerMacOSEmbedded is not initialized."); } if (ds && ret == EXIT_SUCCESS && main_loop) { @@ -1287,7 +1287,7 @@ static void handle_interrupt(int sig) { OS_MacOS_Embedded::OS_MacOS_Embedded(const char *p_execpath, int p_argc, char **p_argv) : OS_MacOS(p_execpath, p_argc, p_argv) { - DisplayServerEmbedded::register_embedded_driver(); + DisplayServerMacOSEmbedded::register_embedded_driver(); } #endif diff --git a/platform/platform_builders.py b/platform/platform_builders.py index 76a7ad0fe615..52595e42c65c 100644 --- a/platform/platform_builders.py +++ b/platform/platform_builders.py @@ -26,6 +26,8 @@ def register_platform_apis_builder(target, source, env): api_inc = "\n".join([f'#include "{p}/api/api.h"' for p in platforms]) api_reg = "\n\t".join([f"register_{p}_api();" for p in platforms]) api_unreg = "\n\t".join([f"unregister_{p}_api();" for p in platforms]) + reg_core_apis = "\n".join([f"\tregister_core_{p}_api();" for p in platforms]) + unreg_core_apis = "\n".join([f"\tunregister_core_{p}_api();" for p in platforms]) with methods.generated_wrapper(str(target[0])) as file: file.write( f"""\ @@ -40,5 +42,13 @@ def register_platform_apis_builder(target, source, env): void unregister_platform_apis() {{ {api_unreg} }} + +void register_core_platform_apis() {{ +{reg_core_apis} +}} + +void unregister_core_platform_apis() {{ +{unreg_core_apis} +}} """ ) diff --git a/platform/register_platform_apis.h b/platform/register_platform_apis.h index 265f313c25e4..dfee8ea2c911 100644 --- a/platform/register_platform_apis.h +++ b/platform/register_platform_apis.h @@ -30,5 +30,7 @@ #pragma once +void register_core_platform_apis(); void register_platform_apis(); +void unregister_core_platform_apis(); void unregister_platform_apis(); diff --git a/platform/visionos/api/api.cpp b/platform/visionos/api/api.cpp index 2b6b89a89f73..a50eadff4f88 100644 --- a/platform/visionos/api/api.cpp +++ b/platform/visionos/api/api.cpp @@ -46,3 +46,9 @@ void register_visionos_api() {} void unregister_visionos_api() {} #endif // VISIONOS_ENABLED + +void register_core_visionos_api() { +} + +void unregister_core_visionos_api() { +} diff --git a/platform/visionos/api/api.h b/platform/visionos/api/api.h index 3b4230d06a82..0c216f67587a 100644 --- a/platform/visionos/api/api.h +++ b/platform/visionos/api/api.h @@ -37,3 +37,6 @@ extern void godot_apple_embedded_plugins_deinitialize(); void register_visionos_api(); void unregister_visionos_api(); + +void register_core_visionos_api(); +void unregister_core_visionos_api(); diff --git a/platform/web/api/api.cpp b/platform/web/api/api.cpp index c8d943577003..1f30faf3e102 100644 --- a/platform/web/api/api.cpp +++ b/platform/web/api/api.cpp @@ -36,6 +36,12 @@ static JavaScriptBridge *javascript_bridge_singleton; +void register_core_web_api() { +} + +void unregister_core_web_api() { +} + void register_web_api() { GDREGISTER_ABSTRACT_CLASS(JavaScriptObject); GDREGISTER_ABSTRACT_CLASS(JavaScriptBridge); @@ -58,7 +64,10 @@ JavaScriptBridge::JavaScriptBridge() { singleton = this; } -JavaScriptBridge::~JavaScriptBridge() {} +JavaScriptBridge::~JavaScriptBridge() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} void JavaScriptBridge::_bind_methods() { ClassDB::bind_method(D_METHOD("eval", "code", "use_global_execution_context"), &JavaScriptBridge::eval, DEFVAL(false)); diff --git a/platform/web/api/api.h b/platform/web/api/api.h index c440da3b9828..bd6ac3ff4a2b 100644 --- a/platform/web/api/api.h +++ b/platform/web/api/api.h @@ -30,5 +30,7 @@ #pragma once +void register_core_web_api(); +void unregister_core_web_api(); void register_web_api(); void unregister_web_api(); diff --git a/platform/web/audio_driver_web.h b/platform/web/audio_driver_web.h index f29c04e1980a..db988382547f 100644 --- a/platform/web/audio_driver_web.h +++ b/platform/web/audio_driver_web.h @@ -166,6 +166,7 @@ class AudioDriverWorklet : public AudioDriverWeb { static AudioDriverWorklet *get_singleton() { return singleton; } AudioDriverWorklet() { singleton = this; } + ~AudioDriverWorklet() { singleton = nullptr; } }; #endif // THREADS_ENABLED @@ -189,4 +190,5 @@ class AudioDriverScriptProcessor : public AudioDriverWeb { static AudioDriverScriptProcessor *get_singleton() { return singleton; } AudioDriverScriptProcessor() { singleton = this; } + ~AudioDriverScriptProcessor() { singleton = nullptr; } }; diff --git a/platform/windows/SCsub b/platform/windows/SCsub index 0df1710a8952..6471b8346a99 100644 --- a/platform/windows/SCsub +++ b/platform/windows/SCsub @@ -26,6 +26,11 @@ common_win = [ "wgl_detect_version.cpp", "rendering_context_driver_vulkan_windows.cpp", "drop_target_windows.cpp", + "rendering_native_surface_windows.cpp", +] + +libgodot_files = [ + "libgodot_windows.cpp", ] if env.msvc: @@ -45,11 +50,11 @@ if env["arch"] == "x86_64": if env.msvc: if "/d2archSSE42" in env_cpp_check["CCFLAGS"]: env_cpp_check["CCFLAGS"].remove("/d2archSSE42") - env.Append(LINKFLAGS=["/ENTRY:ShimMainCRTStartup"]) + env_cpp_check.Append(LINKFLAGS=["/ENTRY:ShimMainCRTStartup"]) else: if "-msse4.2" in env_cpp_check["CCFLAGS"]: env_cpp_check["CCFLAGS"].remove("-msse4.2") - env.Append(LINKFLAGS=["-Wl,--entry=ShimMainCRTStartup"]) + env_cpp_check.Append(LINKFLAGS=["-Wl,--entry=ShimMainCRTStartup"]) def arrange_program_clean(prog): @@ -76,30 +81,41 @@ sources += res_obj if env["accesskit"] and not env.msvc: sources += env.DEFLIB("uiautomationcore") -prog = env.add_program("#bin/godot", sources, PROGSUFFIX=env["PROGSUFFIX"]) -arrange_program_clean(prog) - -if env.msvc: - env.Depends(prog, "godot.natvis") - -# Build console wrapper app. -if env["windows_subsystem"] == "gui": - res_wrap_file = "godot_res_wrap.rc" - res_wrap_target = "godot_res_wrap" + env["OBJSUFFIX"] - res_wrap_obj = env_wrap.RES(res_wrap_target, res_wrap_file) - env_wrap.Depends(res_wrap_obj, "#core/version_generated.gen.h") +if env["library_type"] == "static_library": + prog = env.add_library("#bin/godot", sources + libgodot_files) + arrange_program_clean(prog) +elif env["library_type"] == "shared_library": + prog = env.add_shared_library("#bin/godot", sources + libgodot_files) + env.Append(CPPDEFINES=["EMBEDDED"]) + arrange_program_clean(prog) +else: # building executable + prog = env.add_program("#bin/godot", sources, PROGSUFFIX=env["PROGSUFFIX"]) + arrange_program_clean(prog) if env.msvc: - env_wrap.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"]) - env_wrap.Append(LINKFLAGS=["version.lib"]) - else: - env_wrap.Append(LINKFLAGS=["-Wl,--subsystem,console"]) - 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) - sources += common_win_wrap + res_wrap_obj + env.Depends(prog, "godot.natvis") + + # Build console wrapper app. + if env["windows_subsystem"] == "gui": + env_wrap = env.Clone() + res_wrap_file = "godot_res_wrap.rc" + res_wrap_target = "godot_res_wrap" + env["OBJSUFFIX"] + res_wrap_obj = env_wrap.RES(res_wrap_target, res_wrap_file) + env_wrap.Depends(res_wrap_obj, "#core/version_generated.gen.h") + + if env.msvc: + env_wrap.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"]) + env_wrap.Append(LINKFLAGS=["version.lib"]) + else: + env_wrap.Append(LINKFLAGS=["-Wl,--subsystem,console"]) + 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) + sources += common_win_wrap + res_wrap_obj if env["d3d12"]: dxc_target_aliases = { diff --git a/platform/windows/api/api.cpp b/platform/windows/api/api.cpp new file mode 100644 index 000000000000..3d7888d5e4cd --- /dev/null +++ b/platform/windows/api/api.cpp @@ -0,0 +1,51 @@ +/**************************************************************************/ +/* api.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 "api.h" + +#ifdef WINDOWS_ENABLED +#include "core/object/class_db.h" +#include "platform/windows/rendering_native_surface_windows.h" +#endif + +void register_core_windows_api() { +#ifdef WINDOWS_ENABLED + GDREGISTER_ABSTRACT_CLASS(RenderingNativeSurfaceWindows); +#endif +} + +void unregister_core_windows_api() { +} + +void register_windows_api() { +} + +void unregister_windows_api() { +} diff --git a/platform/windows/api/api.h b/platform/windows/api/api.h new file mode 100644 index 000000000000..284653c6c48d --- /dev/null +++ b/platform/windows/api/api.h @@ -0,0 +1,36 @@ +/**************************************************************************/ +/* api.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. */ +/**************************************************************************/ + +#pragma once + +void register_core_windows_api(); +void unregister_core_windows_api(); +void register_windows_api(); +void unregister_windows_api(); diff --git a/platform/windows/detect.py b/platform/windows/detect.py index 518a5cf67324..d5a8eb5f8591 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -243,7 +243,7 @@ def configure_msvc(env: "SConsEnvironment"): ## Build type # TODO: Re-evaluate the need for this / streamline with common config. - if env["target"] == "template_release": + if env["target"] == "template_release" and env["library_type"] == "executable": env.Append(LINKFLAGS=["/ENTRY:mainCRTStartup"]) if env["windows_subsystem"] == "gui": diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index ac8e084a5c41..63fbdd9c9dc1 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -49,6 +49,8 @@ #include "servers/rendering/dummy/rasterizer_dummy.h" +#include "rendering_native_surface_windows.h" + #if defined(VULKAN_ENABLED) #include "rendering_context_driver_vulkan_windows.h" #endif @@ -3867,6 +3869,10 @@ void DisplayServerWindows::swap_buffers() { #endif } +uint64_t DisplayServerWindows::get_native_window_id(WindowID p_id) const { + return 0; +} + void DisplayServerWindows::set_native_icon(const String &p_filename) { _THREAD_SAFE_METHOD_ @@ -6462,37 +6468,40 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, GetClientRect(wd.hWnd, &real_client_rect); #ifdef RD_ENABLED - if (rendering_context) { - union { -#ifdef VULKAN_ENABLED - RenderingContextDriverVulkanWindows::WindowPlatformData vulkan; -#endif -#ifdef D3D12_ENABLED - RenderingContextDriverD3D12::WindowPlatformData d3d12; + Ref windows_surface = nullptr; +#if defined(VULKAN_ENABLED) || defined(D3D12_ENABLED) + if (rendering_driver == "vulkan" || rendering_driver == "d3d12") { + windows_surface = RenderingNativeSurfaceWindows::create(wd.hWnd, hInstance); + } #endif - } wpd; -#ifdef VULKAN_ENABLED - if (rendering_driver == "vulkan") { - wpd.vulkan.window = wd.hWnd; - wpd.vulkan.instance = hInstance; + if (!rendering_context) { + if (windows_surface.is_valid()) { + rendering_context = windows_surface->create_rendering_context(rendering_driver); } -#endif -#ifdef D3D12_ENABLED - if (rendering_driver == "d3d12") { - wpd.d3d12.window = wd.hWnd; + + if (rendering_context) { + if (rendering_context->initialize() != OK) { + memdelete(rendering_context); + rendering_context = nullptr; + return INVALID_WINDOW_ID; + } } -#endif - if (rendering_context->window_create(id, &wpd) != OK) { + } + + if (rendering_context) { + if (rendering_context->window_create(id, windows_surface) != OK) { ERR_PRINT(vformat("Failed to create %s window.", rendering_driver)); memdelete(rendering_context); rendering_context = nullptr; windows.erase(id); + windows_surface = nullptr; return INVALID_WINDOW_ID; } rendering_context->window_set_size(id, real_client_rect.right - real_client_rect.left - off_x, real_client_rect.bottom - real_client_rect.top); rendering_context->window_set_vsync_mode(id, p_vsync_mode); wd.context_created = true; + windows_surface = nullptr; } #endif diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 4c920e66f35d..4a1b5dde58d6 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -698,6 +698,7 @@ class DisplayServerWindows : public DisplayServer { virtual void release_rendering_thread() override; virtual void swap_buffers() override; + virtual uint64_t get_native_window_id(WindowID p_id = MAIN_WINDOW_ID) const override; virtual void set_native_icon(const String &p_filename) override; virtual void set_icon(const Ref &p_icon) override; diff --git a/platform/windows/libgodot_windows.cpp b/platform/windows/libgodot_windows.cpp new file mode 100644 index 000000000000..fac137fa5719 --- /dev/null +++ b/platform/windows/libgodot_windows.cpp @@ -0,0 +1,77 @@ +/**************************************************************************/ +/* libgodot_windows.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 "core/extension/libgodot.h" + +#include "core/extension/godot_instance.h" +#include "core/io/libgodot_logger.h" +#include "main/main.h" + +#include "os_windows.h" + +static OS_Windows *os = nullptr; + +static GodotInstance *instance = nullptr; + +GDExtensionObjectPtr libgodot_create_godot_instance(int p_argc, char *p_argv[], GDExtensionInitializationFunction p_init_func, InvokeCallbackFunction p_async_func, ExecutorData p_async_data, InvokeCallbackFunction p_sync_func, ExecutorData p_sync_data, LogCallbackFunction p_log_func, LogCallbackData p_log_data, void *p_platform_data) { + ERR_FAIL_COND_V_MSG(instance != nullptr, nullptr, "Only one Godot Instance may be created."); + + os = new OS_Windows((HINSTANCE)p_platform_data); + + if (p_log_func != nullptr && p_log_data != nullptr) { + LibGodotLogger *logger = memnew(LibGodotLogger); + logger->set_callback_function(p_log_func, p_log_data); + os->add_logger(logger); + } + + Error err = Main::setup(p_argv[0], p_argc - 1, &p_argv[1], false); + if (err != OK) { + return nullptr; + } + + instance = memnew(GodotInstance); + if (!instance->initialize(p_init_func)) { + memdelete(instance); + instance = nullptr; + return nullptr; + } + + return (GDExtensionObjectPtr)instance; +} + +void libgodot_destroy_godot_instance(GDExtensionObjectPtr p_godot_instance) { + GodotInstance *godot_instance = (GodotInstance *)p_godot_instance; + if (instance == godot_instance) { + godot_instance->stop(); + memdelete(godot_instance); + instance = nullptr; + Main::cleanup(); + } +} diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 6c76e538ded9..f474310ceadd 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -30,7 +30,11 @@ #include "os_windows.h" +#ifdef EMBEDDED +#include "servers/display_server_embedded.h" +#else #include "display_server_windows.h" +#endif #include "lang_table.h" #include "windows_terminal_logger.h" #include "windows_utils.h" @@ -596,6 +600,9 @@ String OS_Windows::get_distribution_name() const { } String OS_Windows::get_version() const { +#ifdef EMBEDDED + return ""; +#else RtlGetVersionPtr version_ptr = (RtlGetVersionPtr)(void *)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlGetVersion"); if (version_ptr != nullptr) { RTL_OSVERSIONINFOEXW fow; @@ -606,9 +613,11 @@ String OS_Windows::get_version() const { } } return ""; +#endif } String OS_Windows::get_version_alias() const { +#ifndef EMBEDDED RtlGetVersionPtr version_ptr = (RtlGetVersionPtr)(void *)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlGetVersion"); if (version_ptr != nullptr) { RTL_OSVERSIONINFOEXW fow; @@ -644,6 +653,7 @@ String OS_Windows::get_version_alias() const { return vformat("%s (build %d)", windows_string, (int64_t)fow.dwBuildNumber); } } +#endif return ""; } @@ -2580,12 +2590,14 @@ void OS_Windows::add_frame_delay(bool p_can_draw, bool p_wake_for_events) { return; } +#ifndef EMBEDDED DisplayServer *ds = DisplayServer::get_singleton(); DisplayServerWindows *ds_win = Object::cast_to(ds); if (ds_win) { MsgWaitForMultipleObjects(0, nullptr, false, Math::floor(double(delay) / 1000.0), QS_ALLINPUT); return; } +#endif } const uint32_t frame_delay = Engine::get_singleton()->get_frame_delay(); @@ -2769,7 +2781,11 @@ OS_Windows::OS_Windows(HINSTANCE _hInstance) { AudioDriverManager::add_driver(&driver_xaudio2); #endif +#ifdef EMBEDDED + DisplayServerEmbedded::register_embedded_driver(); +#else DisplayServerWindows::register_windows_driver(); +#endif // Enable ANSI escape code support on Windows 10 v1607 (Anniversary Update) and later. // This lets the engine and projects use ANSI escape codes to color text just like on macOS and Linux. diff --git a/platform/windows/rendering_context_driver_vulkan_windows.cpp b/platform/windows/rendering_context_driver_vulkan_windows.cpp index 8ca677fe648c..7970799d9244 100644 --- a/platform/windows/rendering_context_driver_vulkan_windows.cpp +++ b/platform/windows/rendering_context_driver_vulkan_windows.cpp @@ -32,8 +32,12 @@ #include "core/os/os.h" +#include "drivers/vulkan/rendering_native_surface_vulkan.h" #include "rendering_context_driver_vulkan_windows.h" +#include "drivers/vulkan/rendering_native_surface_vulkan.h" +#include "rendering_native_surface_windows.h" + #include "drivers/vulkan/godot_vulkan.h" const char *RenderingContextDriverVulkanWindows::_get_platform_surface_extension() const { @@ -51,21 +55,22 @@ RenderingContextDriverVulkanWindows::~RenderingContextDriverVulkanWindows() { // Does nothing. } -RenderingContextDriver::SurfaceID RenderingContextDriverVulkanWindows::surface_create(const void *p_platform_data) { - const WindowPlatformData *wpd = (const WindowPlatformData *)(p_platform_data); +RenderingContextDriver::SurfaceID RenderingContextDriverVulkanWindows::surface_create(Ref p_native_surface) { + Ref windows_native_surface = Object::cast_to(*p_native_surface); + ERR_FAIL_COND_V(windows_native_surface.is_null(), SurfaceID()); VkWin32SurfaceCreateInfoKHR create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; - create_info.hinstance = wpd->instance; - create_info.hwnd = wpd->window; + create_info.hinstance = windows_native_surface->get_instance(); + create_info.hwnd = windows_native_surface->get_window_handle(); VkSurfaceKHR vk_surface = VK_NULL_HANDLE; VkResult err = vkCreateWin32SurfaceKHR(instance_get(), &create_info, get_allocation_callbacks(VK_OBJECT_TYPE_SURFACE_KHR), &vk_surface); ERR_FAIL_COND_V(err != VK_SUCCESS, SurfaceID()); - Surface *surface = memnew(Surface); - surface->vk_surface = vk_surface; - return SurfaceID(surface); + Ref vulkan_surface = RenderingNativeSurfaceVulkan::create(vk_surface); + RenderingContextDriver::SurfaceID result = RenderingContextDriverVulkan::surface_create(vulkan_surface); + return result; } #endif // WINDOWS_ENABLED && VULKAN_ENABLED diff --git a/platform/windows/rendering_context_driver_vulkan_windows.h b/platform/windows/rendering_context_driver_vulkan_windows.h index be674c480a3c..e82364170ca0 100644 --- a/platform/windows/rendering_context_driver_vulkan_windows.h +++ b/platform/windows/rendering_context_driver_vulkan_windows.h @@ -33,23 +33,16 @@ #ifdef VULKAN_ENABLED #include "drivers/vulkan/rendering_context_driver_vulkan.h" - -#define WIN32_LEAN_AND_MEAN -#include +#include "platform/windows/rendering_native_surface_windows.h" class RenderingContextDriverVulkanWindows : public RenderingContextDriverVulkan { private: const char *_get_platform_surface_extension() const override final; protected: - SurfaceID surface_create(const void *p_platform_data) override final; + SurfaceID surface_create(Ref p_native_surface) override final; public: - struct WindowPlatformData { - HWND window; - HINSTANCE instance; - }; - RenderingContextDriverVulkanWindows(); ~RenderingContextDriverVulkanWindows() override; }; diff --git a/platform/windows/rendering_native_surface_windows.cpp b/platform/windows/rendering_native_surface_windows.cpp new file mode 100644 index 000000000000..8442749481fe --- /dev/null +++ b/platform/windows/rendering_native_surface_windows.cpp @@ -0,0 +1,77 @@ +/**************************************************************************/ +/* rendering_native_surface_windows.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_native_surface_windows.h" +#include "rendering_context_driver_vulkan_windows.h" + +#if defined(D3D12_ENABLED) +#include "drivers/d3d12/rendering_context_driver_d3d12.h" +#endif + +#if defined(VULKAN_ENABLED) +#include "platform/windows/rendering_context_driver_vulkan_windows.h" +#endif + +void RenderingNativeSurfaceWindows::_bind_methods() { + ClassDB::bind_static_method("RenderingNativeSurfaceWindows", D_METHOD("create_api", "hwnd", "instance"), &RenderingNativeSurfaceWindows::create_api); +} + +Ref RenderingNativeSurfaceWindows::create_api(GDExtensionConstPtr p_window, GDExtensionConstPtr p_instance) { + return RenderingNativeSurfaceWindows::create((HWND)p_window.operator const void *(), (HINSTANCE)p_instance.operator const void *()); +} + +Ref RenderingNativeSurfaceWindows::create(HWND p_window, HINSTANCE p_instance) { + Ref result = memnew(RenderingNativeSurfaceWindows); + result->window = p_window; + result->instance = p_instance; + return result; +} + +RenderingContextDriver *RenderingNativeSurfaceWindows::create_rendering_context(const String &p_driver_name) { +#if defined(VULKAN_ENABLED) + if (p_driver_name == "vulkan") { + return memnew(RenderingContextDriverVulkanWindows); + } +#endif +#if defined(D3D12_ENABLED) + if (p_driver_name == "d3d12") { + return memnew(RenderingContextDriverD3D12); + } +#endif + return nullptr; +} + +RenderingNativeSurfaceWindows::RenderingNativeSurfaceWindows() { + // Does nothing. +} + +RenderingNativeSurfaceWindows::~RenderingNativeSurfaceWindows() { + // Does nothing. +} diff --git a/platform/windows/rendering_native_surface_windows.h b/platform/windows/rendering_native_surface_windows.h new file mode 100644 index 000000000000..f7b65e088bc2 --- /dev/null +++ b/platform/windows/rendering_native_surface_windows.h @@ -0,0 +1,70 @@ +/**************************************************************************/ +/* rendering_native_surface_windows.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. */ +/**************************************************************************/ + +#pragma once + +#include "core/variant/native_ptr.h" +#include "servers/rendering/rendering_native_surface.h" + +#define WIN32_LEAN_AND_MEAN +#include + +class RenderingNativeSurfaceWindows : public RenderingNativeSurface { +public: +private: + GDCLASS(RenderingNativeSurfaceWindows, RenderingNativeSurface); + + static void _bind_methods(); + + HWND window; + HINSTANCE instance; + +public: + static Ref create_api(GDExtensionConstPtr p_window, GDExtensionConstPtr p_instance); + + static Ref create(HWND p_window, HINSTANCE p_instance); + + HWND get_window_handle() const { + return window; + } + + HINSTANCE get_instance() const { + return instance; + } + + virtual void *get_native_id() const override { + return (void *)window; + } + + RenderingContextDriver *create_rendering_context(const String &p_driver_name) override; + + RenderingNativeSurfaceWindows(); + ~RenderingNativeSurfaceWindows(); +}; diff --git a/platform_methods.py b/platform_methods.py index 6a50fb6dc165..c170284ed822 100644 --- a/platform_methods.py +++ b/platform_methods.py @@ -168,7 +168,11 @@ def combine_libs_apple_embedded(target, source, env): else: libtool = "$APPLE_TOOLCHAIN_PATH/usr/bin/libtool" env.Execute( - libtool + ' -static -o "' + lib_path + '" ' + " ".join([('"' + lib.srcnode().abspath + '"') for lib in source]) + libtool + + ' -static -a -o "' + + lib_path + + '" ' + + " ".join([('"' + lib.srcnode().abspath + '"') for lib in source]) ) diff --git a/scene/debugger/scene_debugger.cpp b/scene/debugger/scene_debugger.cpp index 36ef16acac53..5ef2e8b4c99f 100644 --- a/scene/debugger/scene_debugger.cpp +++ b/scene/debugger/scene_debugger.cpp @@ -1499,6 +1499,9 @@ RuntimeNodeSelect::~RuntimeNodeSelect() { RS::get_singleton()->free(sbox_2d_ci); RS::get_singleton()->free(draw_canvas); } + + ERR_FAIL_COND(singleton != this); + singleton = nullptr; } void RuntimeNodeSelect::_setup(const Dictionary &p_settings) { diff --git a/scene/debugger/scene_debugger.h b/scene/debugger/scene_debugger.h index c4a8438aea4b..ec416bdb62bd 100644 --- a/scene/debugger/scene_debugger.h +++ b/scene/debugger/scene_debugger.h @@ -228,6 +228,11 @@ class LiveEditor { inline static LiveEditor *singleton = nullptr; public: + ~LiveEditor() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; + } + static LiveEditor *get_singleton(); }; diff --git a/scene/main/window.cpp b/scene/main/window.cpp index 5d1694973cf7..056d08135706 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -638,6 +638,17 @@ bool Window::is_in_edited_scene_root() const { void Window::_make_window() { ERR_FAIL_COND(window_id != DisplayServer::INVALID_WINDOW_ID); + if (native_surface != nullptr) { + window_id = DisplayServer::get_singleton()->create_native_window(native_surface); + ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID); + + _update_window_size(); + + _update_window_callbacks(); + + RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_VISIBLE); + return; + } if (transient && transient_to_focused) { _make_transient(); @@ -700,6 +711,13 @@ void Window::_update_from_window() { void Window::_clear_window() { ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID); + if (native_surface != nullptr) { + DisplayServer::get_singleton()->delete_native_window(window_id); + window_id = DisplayServer::INVALID_WINDOW_ID; + + RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED); + return; + } bool had_focus = has_focus(); @@ -908,6 +926,11 @@ void Window::_accessibility_notify_exit(Node *p_node) { void Window::set_visible(bool p_visible) { ERR_MAIN_THREAD_GUARD; + if (native_surface.is_valid()) { + visible = true; + return; + } + if (visible == p_visible) { return; } @@ -999,6 +1022,33 @@ void Window::_clear_transient() { } } +void Window::set_native_surface(Ref p_native_surface) { + Ref new_native_handle = p_native_surface; + if (new_native_handle == native_surface) { + return; + } + if (!initialized) { + native_surface = new_native_handle; + return; + } + if (embedder) { + embedder->_sub_window_remove(this); + } else { + _clear_window(); + } + native_surface = new_native_handle; + embedder = get_embedder(); + if (embedder) { + embedder->_sub_window_register(this); + } else { + _make_window(); + } +} + +Ref Window::get_native_surface() { + return native_surface; +} + void Window::_make_transient() { if (!get_parent()) { //main window, can't be transient @@ -1361,6 +1411,10 @@ Viewport *Window::get_embedder() const { return nullptr; } + if (native_surface != nullptr) { + return nullptr; + } + Viewport *vp = get_parent_viewport(); while (vp) { @@ -3184,6 +3238,9 @@ void Window::_bind_methods() { ClassDB::bind_method(D_METHOD("set_visible", "visible"), &Window::set_visible); ClassDB::bind_method(D_METHOD("is_visible"), &Window::is_visible); + ClassDB::bind_method(D_METHOD("set_native_surface", "native_surface"), &Window::set_native_surface); + ClassDB::bind_method(D_METHOD("get_native_surface"), &Window::get_native_surface); + ClassDB::bind_method(D_METHOD("hide"), &Window::hide); ClassDB::bind_method(D_METHOD("show"), &Window::show); diff --git a/scene/main/window.h b/scene/main/window.h index 64d99a4ff821..21344c6cd40c 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -33,6 +33,7 @@ #include "scene/main/viewport.h" #include "scene/resources/theme.h" #include "servers/display_server.h" +#include "servers/rendering/rendering_native_surface.h" class Font; class Shortcut; @@ -181,6 +182,8 @@ class Window : public Viewport { void _update_window_callbacks(); + Ref native_surface; + Window *transient_parent = nullptr; Window *exclusive_child = nullptr; HashSet transient_children; @@ -344,6 +347,9 @@ class Window : public Viewport { virtual void set_visible(bool p_visible); bool is_visible() const; + void set_native_surface(Ref p_native_surface); + Ref get_native_surface(); + void update_mouse_cursor_state() override; void show(); diff --git a/scene/resources/3d/sky_material.cpp b/scene/resources/3d/sky_material.cpp index 981256e9fa03..5e91e673fe32 100644 --- a/scene/resources/3d/sky_material.cpp +++ b/scene/resources/3d/sky_material.cpp @@ -291,6 +291,8 @@ void ProceduralSkyMaterial::cleanup_shader() { RS::get_singleton()->free(shader_cache[i]); } } + shader_cache[0] = RID(); + shader_cache[1] = RID(); } void ProceduralSkyMaterial::_update_shader(bool p_use_debanding, bool p_use_sky_cover) { @@ -481,6 +483,8 @@ void PanoramaSkyMaterial::cleanup_shader() { RS::get_singleton()->free(shader_cache[i]); } } + shader_cache[0] = RID(); + shader_cache[1] = RID(); } void PanoramaSkyMaterial::_update_shader(bool p_filter) { @@ -723,6 +727,8 @@ void PhysicalSkyMaterial::cleanup_shader() { RS::get_singleton()->free(shader_cache[i]); } } + shader_cache[0] = RID(); + shader_cache[1] = RID(); } void PhysicalSkyMaterial::_update_shader(bool p_use_debanding, bool p_use_night_sky) { diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index 3665fdd4e95a..6627443289e1 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -2170,3 +2170,8 @@ ResourceFormatSaverText *ResourceFormatSaverText::singleton = nullptr; ResourceFormatSaverText::ResourceFormatSaverText() { singleton = this; } + +ResourceFormatSaverText::~ResourceFormatSaverText() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} diff --git a/scene/resources/resource_format_text.h b/scene/resources/resource_format_text.h index 644b90b3ebd2..9e2eb6d85059 100644 --- a/scene/resources/resource_format_text.h +++ b/scene/resources/resource_format_text.h @@ -211,4 +211,5 @@ class ResourceFormatSaverText : public ResourceFormatSaver { virtual void get_recognized_extensions(const Ref &p_resource, List *p_extensions) const override; ResourceFormatSaverText(); + ~ResourceFormatSaverText(); }; diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp index 08d27f13c3dd..ce980f058256 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -100,11 +100,23 @@ void Shader::set_code(const String &p_code) { // 2) Server does not do interaction with Resource filetypes, this is a scene level feature. HashSet> new_include_dependencies; ShaderPreprocessor preprocessor; - Error result = preprocessor.preprocess(p_code, path, preprocessed_code, nullptr, nullptr, nullptr, &new_include_dependencies); - if (result == OK) { - // This ensures previous include resources are not freed and then re-loaded during parse (which would make compiling slower) - include_dependencies = new_include_dependencies; + String error_pp; + List err_positions; + Error result = preprocessor.preprocess(p_code, path, preprocessed_code, &error_pp, &err_positions, nullptr, &new_include_dependencies); + if (result != OK) { + ERR_FAIL_COND(err_positions.is_empty()); + + String err_text = error_pp; + int err_line = err_positions.front()->get().line; + if (err_positions.size() == 1) { + // Error in main file + err_text = "error(" + itos(err_line) + "): " + err_text; + } else { + err_text = "error(" + itos(err_line) + ") in include " + err_positions.back()->get().file.get_file() + ":" + itos(err_positions.back()->get().line) + ": " + err_text; + } + ERR_FAIL_MSG(vformat("Preprocessing shader %s failed: %s", path, err_text)); } + include_dependencies = new_include_dependencies; } // Try to get the shader type from the final, fully preprocessed shader code. @@ -329,6 +341,47 @@ Ref ResourceFormatLoaderShader::load(const String &p_path, const Strin return shader; } +void ResourceFormatLoaderShader::get_dependencies(const String &p_path, List *p_dependencies, bool p_add_types) { + Error error = OK; + Vector buffer = FileAccess::get_file_as_bytes(p_path, &error); + ERR_FAIL_COND_MSG(error, "Cannot load shader: " + p_path); + + String str; + if (buffer.size() > 0) { + error = str.append_utf8((const char *)buffer.ptr(), buffer.size()); + ERR_FAIL_COND_MSG(error, "Cannot parse shader: " + p_path); + } + + { + HashSet> new_include_dependencies; + ShaderPreprocessor preprocessor; + String preprocessed_code; + String error_pp; + List err_positions; + Error result = preprocessor.preprocess(str, p_path, preprocessed_code, &error_pp, &err_positions, nullptr, &new_include_dependencies); + if (result != OK) { + ERR_FAIL_COND(err_positions.is_empty()); + + String err_text = error_pp; + int err_line = err_positions.front()->get().line; + if (err_positions.size() == 1) { + // Error in main file + err_text = "error(" + itos(err_line) + "): " + err_text; + } else { + err_text = "error(" + itos(err_line) + ") in include " + err_positions.back()->get().file.get_file() + ":" + itos(err_positions.back()->get().line) + ": " + err_text; + } + ERR_FAIL_MSG(vformat("Preprocessing shader %s failed: %s", p_path, err_text)); + } + if (p_dependencies) { + List deps; + for (Ref inc : new_include_dependencies) { + deps.push_back(inc->get_path()); + } + *p_dependencies = deps; + } + } +} + void ResourceFormatLoaderShader::get_recognized_extensions(List *p_extensions) const { p_extensions->push_back("gdshader"); } diff --git a/scene/resources/shader.h b/scene/resources/shader.h index 312b90dacc75..06d43863ed05 100644 --- a/scene/resources/shader.h +++ b/scene/resources/shader.h @@ -108,6 +108,7 @@ VARIANT_ENUM_CAST(Shader::Mode); class ResourceFormatLoaderShader : public ResourceFormatLoader { public: virtual Ref load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override; + virtual void get_dependencies(const String &p_path, List *p_dependencies, bool p_add_types = false) override; virtual void get_recognized_extensions(List *p_extensions) const override; virtual bool handles_type(const String &p_type) const override; virtual String get_resource_type(const String &p_path) const override; diff --git a/servers/SCsub b/servers/SCsub index 88fddce580af..ce7411ad6216 100644 --- a/servers/SCsub +++ b/servers/SCsub @@ -8,6 +8,8 @@ env.servers_sources = [] env.add_source_files(env.servers_sources, "audio_server.cpp") env.add_source_files(env.servers_sources, "camera_server.cpp") env.add_source_files(env.servers_sources, "display_server.cpp") +env.add_source_files(env.servers_sources, "display_server_embedded_host_interface.cpp") +env.add_source_files(env.servers_sources, "display_server_embedded.cpp") env.add_source_files(env.servers_sources, "navigation_server_2d.cpp") env.add_source_files(env.servers_sources, "navigation_server_3d.cpp") env.add_source_files(env.servers_sources, "register_server_types.cpp") diff --git a/servers/audio/audio_driver_dummy.cpp b/servers/audio/audio_driver_dummy.cpp index 3d1070a6cb67..ec39a95e678f 100644 --- a/servers/audio/audio_driver_dummy.cpp +++ b/servers/audio/audio_driver_dummy.cpp @@ -148,3 +148,8 @@ void AudioDriverDummy::finish() { AudioDriverDummy::AudioDriverDummy() { singleton = this; } + +AudioDriverDummy::~AudioDriverDummy() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} diff --git a/servers/audio/audio_driver_dummy.h b/servers/audio/audio_driver_dummy.h index af60aa10a435..75afa15260cf 100644 --- a/servers/audio/audio_driver_dummy.h +++ b/servers/audio/audio_driver_dummy.h @@ -82,5 +82,5 @@ class AudioDriverDummy : public AudioDriver { static AudioDriverDummy *get_dummy_singleton() { return singleton; } AudioDriverDummy(); - ~AudioDriverDummy() {} + ~AudioDriverDummy(); }; diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index 07d38316496b..62767a4edc56 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -58,6 +58,12 @@ void AudioDriver::set_singleton() { singleton = this; } +AudioDriver::~AudioDriver() { + if (singleton == this) { + singleton = nullptr; + } +} + void AudioDriver::audio_server_process(int p_frames, int32_t *p_buffer, bool p_update_mix_time) { if (p_update_mix_time) { update_mix_time(p_frames); @@ -250,6 +256,11 @@ AudioDriver *AudioDriverManager::get_driver(int p_driver) { return drivers[p_driver]; } +void AudioDriverManager::reset() { + drivers[0] = &AudioDriverManager::dummy_driver; + driver_count = 1; +} + ////////////////////////////////////////////// ////////////////////////////////////////////// ////////////////////////////////////////////// diff --git a/servers/audio_server.h b/servers/audio_server.h index e429c83616b2..521a7033e174 100644 --- a/servers/audio_server.h +++ b/servers/audio_server.h @@ -155,7 +155,7 @@ class AudioDriver { virtual void set_sample_bus_mute(int p_bus, bool p_enable) {} AudioDriver() {} - virtual ~AudioDriver() {} + virtual ~AudioDriver(); }; class AudioDriverManager { @@ -175,6 +175,7 @@ class AudioDriverManager { static void initialize(int p_driver); static int get_driver_count(); static AudioDriver *get_driver(int p_driver); + static void reset(); }; class AudioBusLayout; diff --git a/servers/display_server.cpp b/servers/display_server.cpp index d2acfd8c9835..22a98bfbc86e 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -604,6 +604,18 @@ DisplayServer::WindowID DisplayServer::create_sub_window(WindowMode p_mode, VSyn ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Sub-windows not supported by this display server."); } +DisplayServer::WindowID DisplayServer::create_native_window(Ref p_native_window) { + ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Native windows not supported by this display server."); +} + +bool DisplayServer::is_native_window(DisplayServer::WindowID p_id) { + ERR_FAIL_V_MSG(false, "Native windows not supported by this display server."); +} + +void DisplayServer::delete_native_window(DisplayServer::WindowID p_id) { + ERR_FAIL_MSG("Native windows not supported by this display server."); +} + void DisplayServer::show_window(WindowID p_id) { ERR_FAIL_MSG("Sub-windows not supported by this display server."); } @@ -1215,6 +1227,15 @@ void DisplayServer::swap_buffers() { WARN_PRINT("Swap buffers not supported by this display server."); } +uint64_t DisplayServer::get_native_window_id(WindowID p_id) const { + WARN_PRINT("Native window id not supported by this display server."); + return 0; +} + +bool DisplayServer::is_rendering_flipped() const { + return true; +} + void DisplayServer::set_native_icon(const String &p_filename) { WARN_PRINT("Native icon not supported by this display server."); } @@ -1223,6 +1244,26 @@ void DisplayServer::set_icon(const Ref &p_icon) { WARN_PRINT("Icon not supported by this display server."); } +void DisplayServer::mouse_button(int p_x, int p_y, MouseButton p_mouse_button_index, bool p_pressed, bool p_double_click, bool p_cancelled, DisplayServer::WindowID p_window) { + WARN_PRINT("Mouse button not supported by this display server."); +} + +void DisplayServer::mouse_motion(int p_prev_x, int p_prev_y, int p_x, int p_y, DisplayServer::WindowID p_window) { + WARN_PRINT("Mouse motion not supported by this display server."); +} + +void DisplayServer::touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_double_click, DisplayServer::WindowID p_window) { + WARN_PRINT("Touch press not supported by this display server."); +} + +void DisplayServer::touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y, float p_pressure, Vector2 p_tilt, DisplayServer::WindowID p_window) { + WARN_PRINT("Touch drag not supported by this display server."); +} + +void DisplayServer::key(Key p_key, char32_t p_char, Key p_unshifted, Key p_physical, BitField p_modifiers, bool p_pressed, DisplayServer::WindowID p_window) { + WARN_PRINT("Key press not supported by this display server."); +} + DisplayServer::IndicatorID DisplayServer::create_status_indicator(const Ref &p_icon, const String &p_tooltip, const Callable &p_callback) { WARN_PRINT("Status indicator not supported by this display server."); return INVALID_INDICATOR_ID; @@ -1602,6 +1643,12 @@ void DisplayServer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_native_icon", "filename"), &DisplayServer::set_native_icon); ClassDB::bind_method(D_METHOD("set_icon", "image"), &DisplayServer::set_icon); + ClassDB::bind_method(D_METHOD("mouse_button", "x", "y", "mouse_button_index", "pressed", "double_click", "cancelled", "window"), &DisplayServer::mouse_button); + ClassDB::bind_method(D_METHOD("mouse_motion", "prev_x", "prev_y", "x", "y", "window"), &DisplayServer::mouse_motion); + ClassDB::bind_method(D_METHOD("touch_press", "idx", "x", "y", "pressed", "double_click", "window"), &DisplayServer::touch_press); + ClassDB::bind_method(D_METHOD("touch_drag", "idx", "prev_x", "prev_y", "x", "y", "pressure", "tilt", "window"), &DisplayServer::touch_drag); + ClassDB::bind_method(D_METHOD("key", "key", "char", "unshifted", "physical", "modifiers", "pressed", "window"), &DisplayServer::key); + ClassDB::bind_method(D_METHOD("create_status_indicator", "icon", "tooltip", "callback"), &DisplayServer::create_status_indicator); ClassDB::bind_method(D_METHOD("status_indicator_set_icon", "id", "icon"), &DisplayServer::status_indicator_set_icon); ClassDB::bind_method(D_METHOD("status_indicator_set_tooltip", "id", "tooltip"), &DisplayServer::status_indicator_set_tooltip); diff --git a/servers/display_server.h b/servers/display_server.h index 6283edc45f9a..4de24df6cddc 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -35,8 +35,9 @@ #include "core/io/resource.h" #include "core/os/os.h" #include "core/variant/callable.h" - #include "display/native_menu.h" +#include "servers/display_server_embedded_host_interface.h" +#include "servers/rendering/rendering_native_surface.h" class Texture2D; class AccessibilityDriver; @@ -84,6 +85,7 @@ class DisplayServer : public Object { OPENGL_CONTEXT, EGL_DISPLAY, EGL_CONFIG, + OPENGL_FBO, }; enum Context { @@ -169,6 +171,7 @@ class DisplayServer : public Object { FEATURE_NATIVE_COLOR_PICKER, FEATURE_SELF_FITTING_WINDOWS, FEATURE_ACCESSIBILITY_SCREEN_READER, + FEATURE_NATIVE_WINDOWS, }; virtual bool has_feature(Feature p_feature) const = 0; @@ -438,6 +441,10 @@ class DisplayServer : public Object { virtual void show_window(WindowID p_id); virtual void delete_sub_window(WindowID p_id); + virtual WindowID create_native_window(Ref p_native_window); + virtual bool is_native_window(WindowID p_id); + virtual void delete_native_window(WindowID p_id); + virtual WindowID window_get_active_popup() const { return INVALID_WINDOW_ID; } virtual void window_set_popup_safe_rect(WindowID p_window, const Rect2i &p_rect) {} virtual Rect2i window_get_popup_safe_rect(WindowID p_window) const { return Rect2i(); } @@ -854,10 +861,20 @@ class DisplayServer : public Object { virtual void release_rendering_thread(); virtual void swap_buffers(); + virtual uint64_t get_native_window_id(WindowID p_id = MAIN_WINDOW_ID) const; + + virtual bool is_rendering_flipped() const; virtual void set_native_icon(const String &p_filename); virtual void set_icon(const Ref &p_icon); + virtual void mouse_button(int p_x, int p_y, MouseButton p_mouse_button_index, bool p_pressed, bool p_double_click, bool p_cancelled, DisplayServer::WindowID p_window); + virtual void mouse_motion(int p_prev_x, int p_prev_y, int p_x, int p_y, DisplayServer::WindowID p_window); + + virtual void touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_double_click, DisplayServer::WindowID p_window); + virtual void touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y, float p_pressure, Vector2 p_tilt, DisplayServer::WindowID p_window); + virtual void key(Key p_key, char32_t p_char, Key p_unshifted, Key p_physical, BitField p_modifiers, bool p_pressed, DisplayServer::WindowID p_window); + virtual IndicatorID create_status_indicator(const Ref &p_icon, const String &p_tooltip, const Callable &p_callback); virtual void status_indicator_set_icon(IndicatorID p_id, const Ref &p_icon); virtual void status_indicator_set_tooltip(IndicatorID p_id, const String &p_tooltip); diff --git a/servers/display_server_embedded.cpp b/servers/display_server_embedded.cpp new file mode 100644 index 000000000000..de7c6e82618e --- /dev/null +++ b/servers/display_server_embedded.cpp @@ -0,0 +1,756 @@ +/**************************************************************************/ +/* display_server_embedded.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 "display_server_embedded.h" + +#include "core/config/project_settings.h" +#include "core/io/file_access_pack.h" +#include "servers/rendering/gl_manager.h" + +#ifdef RD_ENABLED +#if defined(VULKAN_ENABLED) +#include "drivers/vulkan/godot_vulkan.h" +#endif // VULKAN_ENABLED +#endif // RD_ENABLED + +Ref DisplayServerEmbedded::native_surface = nullptr; + +DisplayServerEmbedded *DisplayServerEmbedded::get_singleton() { + return (DisplayServerEmbedded *)DisplayServer::get_singleton(); +} + +void DisplayServerEmbedded::set_native_surface(Ref p_native_surface) { + native_surface = p_native_surface; +} + +void DisplayServerEmbedded::set_screen_get_dpi_callback(Callable p_callback) { + screen_get_dpi_callback = p_callback; +} + +void DisplayServerEmbedded::set_screen_get_size_callback(Callable p_callback) { + screen_get_size_callback = p_callback; +} + +void DisplayServerEmbedded::set_screen_get_scale_callback(Callable p_callback) { + screen_get_scale_callback = p_callback; +} + +void DisplayServerEmbedded::_bind_methods() { + ClassDB::bind_static_method("DisplayServerEmbedded", D_METHOD("set_native_surface", "native_surface"), &DisplayServerEmbedded::set_native_surface); + ClassDB::bind_static_method("DisplayServerEmbedded", D_METHOD("get_singleton"), &DisplayServerEmbedded::get_singleton); + ClassDB::bind_static_method("DisplayServerEmbedded", D_METHOD("set_screen_get_dpi_callback", "callback"), &DisplayServerEmbedded::set_screen_get_dpi_callback); + ClassDB::bind_static_method("DisplayServerEmbedded", D_METHOD("set_screen_get_size_callback", "callback"), &DisplayServerEmbedded::set_screen_get_size_callback); + ClassDB::bind_static_method("DisplayServerEmbedded", D_METHOD("set_screen_get_scale_callback", "callback"), &DisplayServerEmbedded::set_screen_get_scale_callback); + ClassDB::bind_method(D_METHOD("resize_window", "size", "id"), &DisplayServerEmbedded::resize_window); + ClassDB::bind_method(D_METHOD("set_content_scale", "content_scale"), &DisplayServerEmbedded::set_content_scale); + ClassDB::bind_method(D_METHOD("touches_canceled", "idx", "window"), &DisplayServerEmbedded::touches_canceled); + ClassDB::bind_method(D_METHOD("set_host_interface", "host_interface"), &DisplayServerEmbedded::set_host_interface); + ClassDB::bind_method(D_METHOD("delete_host_interface"), &DisplayServerEmbedded::delete_host_interface); +} + +DisplayServerEmbedded::DisplayServerEmbedded(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, Error &r_error) { + ERR_FAIL_NULL_MSG(native_surface, "Native surface has not been set."); + + rendering_driver = p_rendering_driver; + + native_menu = memnew(NativeMenu); + +#if defined(RD_ENABLED) + rendering_context = nullptr; + rendering_device = nullptr; + + if (rendering_driver == "vulkan" || rendering_driver == "metal" || rendering_driver == "d3d12") { + rendering_context = native_surface->create_rendering_context(rendering_driver); + } + + if (rendering_context) { + if (rendering_context->initialize() != OK) { + ERR_PRINT(vformat("Failed to initialize %s context", rendering_driver)); + memdelete(rendering_context); + rendering_context = nullptr; + return; + } + + if (create_native_window(native_surface) != MAIN_WINDOW_ID) { + ERR_PRINT(vformat("Failed to create %s window.", rendering_driver)); + memdelete(rendering_context); + rendering_context = nullptr; + r_error = ERR_UNAVAILABLE; + return; + } + + rendering_device = memnew(RenderingDevice); +#ifdef EXTERNAL_TARGET_ENABLED + bool monitored_frames = true; +#else + bool monitored_frames = false; +#endif + rendering_device->initialize(rendering_context, MAIN_WINDOW_ID, monitored_frames); + rendering_device->screen_create(MAIN_WINDOW_ID); + +#ifdef EXTERNAL_TARGET_ENABLED + native_surface->setup_external_swapchain_callbacks(); +#endif + + RendererCompositorRD::make_current(); + } +#endif + +#if defined(GLES3_ENABLED) + if (rendering_driver.contains("opengl3")) { + gl_manager = native_surface->create_gl_manager(rendering_driver); + + if (gl_manager->initialize() != OK || gl_manager->open_display(nullptr) != OK) { + memdelete(gl_manager); + gl_manager = nullptr; + } + if (create_native_window(native_surface) != MAIN_WINDOW_ID) { + ERR_PRINT(vformat("Failed to create %s window.", rendering_driver)); + r_error = ERR_UNAVAILABLE; + return; + } + } +#endif + + Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events); + + r_error = OK; +} + +DisplayServerEmbedded::~DisplayServerEmbedded() { + if (native_menu) { + memdelete(native_menu); + native_menu = nullptr; + } + +#if defined(RD_ENABLED) + if (rendering_device) { + rendering_device->screen_free(MAIN_WINDOW_ID); + memdelete(rendering_device); + rendering_device = nullptr; + } + + if (rendering_context) { + rendering_context->window_destroy(MAIN_WINDOW_ID); + memdelete(rendering_context); + rendering_context = nullptr; + } +#endif + +#if defined(GLES3_ENABLED) + if (gl_manager) { + memdelete(gl_manager); + gl_manager = nullptr; + } +#endif + // Release native surface + native_surface = nullptr; +} + +DisplayServer *DisplayServerEmbedded::create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, int64_t /* p_parent_window */, Error &r_error) { + return memnew(DisplayServerEmbedded(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, p_context, r_error)); +} + +Vector DisplayServerEmbedded::get_rendering_drivers_func() { + Vector drivers; + +#if defined(VULKAN_ENABLED) + drivers.push_back("vulkan"); +#endif +#if defined(METAL_ENABLED) + drivers.push_back("metal"); +#endif +#if defined(GLES3_ENABLED) + drivers.push_back("opengl3"); +#endif + + return drivers; +} + +void DisplayServerEmbedded::register_embedded_driver() { + register_create_function("embedded", create_func, get_rendering_drivers_func); +} + +// MARK: Events + +void DisplayServerEmbedded::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) { + window_resize_callbacks[p_window] = p_callable; +} + +void DisplayServerEmbedded::window_set_window_event_callback(const Callable &p_callable, WindowID p_window) { + window_event_callbacks[p_window] = p_callable; +} +void DisplayServerEmbedded::window_set_input_event_callback(const Callable &p_callable, WindowID p_window) { + input_event_callbacks[p_window] = p_callable; +} + +void DisplayServerEmbedded::window_set_input_text_callback(const Callable &p_callable, WindowID p_window) { + input_text_callbacks[p_window] = p_callable; +} + +void DisplayServerEmbedded::window_set_drop_files_callback(const Callable &p_callable, WindowID p_window) { + // Not supported +} + +void DisplayServerEmbedded::process_events() { + Input::get_singleton()->flush_buffered_events(); +} + +void DisplayServerEmbedded::_dispatch_input_events(const Ref &p_event) { + Ref event_from_window = p_event; + WindowID window_id = INVALID_WINDOW_ID; + if (event_from_window.is_valid()) { + window_id = event_from_window->get_window_id(); + } + DisplayServerEmbedded::get_singleton()->send_input_event(p_event, window_id); +} + +void DisplayServerEmbedded::send_input_event(const Ref &p_event, WindowID p_id) const { + if (p_id != INVALID_WINDOW_ID) { + _window_callback(input_event_callbacks[p_id], p_event); + } else { + for (const KeyValue &E : input_event_callbacks) { + _window_callback(E.value, p_event); + } + } +} + +void DisplayServerEmbedded::send_input_text(const String &p_text, WindowID p_id) const { + _window_callback(input_text_callbacks[p_id], p_text); +} + +void DisplayServerEmbedded::send_window_event(DisplayServer::WindowEvent p_event, WindowID p_id) const { + _window_callback(window_event_callbacks[p_id], int(p_event)); +} + +void DisplayServerEmbedded::_window_callback(const Callable &p_callable, const Variant &p_arg) const { + if (!p_callable.is_null()) { + p_callable.call(p_arg); + } +} + +// MARK: - Input + +// MARK: Mouse + +void DisplayServerEmbedded::mouse_set_mode(MouseMode p_mode) { + mouse_mode = p_mode; +} + +DisplayServer::MouseMode DisplayServerEmbedded::mouse_get_mode() const { + return mouse_mode; +} + +Point2i DisplayServerEmbedded::mouse_get_position() const { + return mouse_position; +} + +BitField DisplayServerEmbedded::mouse_get_button_state() const { + return mouse_button_state; +} + +void DisplayServerEmbedded::mouse_button(int p_x, int p_y, MouseButton p_mouse_button_index, bool p_pressed, bool p_double_click, bool p_cancelled, DisplayServer::WindowID p_window) { + Ref ev; + ev.instantiate(); + + ev->set_window_id(p_window); + ev->set_button_index(p_mouse_button_index); + ev->set_pressed(p_pressed); + ev->set_double_click(p_double_click); + ev->set_canceled(p_cancelled); + ev->set_position(Vector2(p_x, p_y)); + mouse_position = Point2i(p_x, p_y); + + if (ev->is_pressed()) { + mouse_button_state.set_flag(mouse_button_to_mask(ev->get_button_index())); + } else { + mouse_button_state.clear_flag(mouse_button_to_mask(ev->get_button_index())); + } + ev->set_button_mask(mouse_button_state); + + perform_event(ev); +} + +void DisplayServerEmbedded::mouse_motion(int p_prev_x, int p_prev_y, int p_x, int p_y, DisplayServer::WindowID p_window) { + Ref ev; + ev.instantiate(); + + ev->set_window_id(p_window); + ev->set_position(Vector2(p_x, p_y)); + + mouse_position = Point2i(p_x, p_y); + + ev->set_relative(Vector2(p_x - p_prev_x, p_y - p_prev_y)); + ev->set_button_mask(mouse_button_state); + + perform_event(ev); +} + +// MARK: Touches + +void DisplayServerEmbedded::touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_double_click, DisplayServer::WindowID p_window) { + Ref ev; + ev.instantiate(); + + ev->set_window_id(p_window); + ev->set_index(p_idx); + ev->set_pressed(p_pressed); + ev->set_position(Vector2(p_x, p_y)); + ev->set_double_tap(p_double_click); + perform_event(ev); +} + +void DisplayServerEmbedded::touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y, float p_pressure, Vector2 p_tilt, DisplayServer::WindowID p_window) { + Ref ev; + ev.instantiate(); + ev->set_window_id(p_window); + ev->set_index(p_idx); + ev->set_pressure(p_pressure); + ev->set_tilt(p_tilt); + ev->set_position(Vector2(p_x, p_y)); + ev->set_relative(Vector2(p_x - p_prev_x, p_y - p_prev_y)); + ev->set_relative_screen_position(ev->get_relative()); + perform_event(ev); +} + +void DisplayServerEmbedded::perform_event(const Ref &p_event) { + Input::get_singleton()->parse_input_event(p_event); +} + +void DisplayServerEmbedded::touches_canceled(int p_idx, DisplayServer::WindowID p_window) { + touch_press(p_idx, -1, -1, false, false, p_window); +} + +void DisplayServerEmbedded::key(Key p_key, char32_t p_char, Key p_unshifted, Key p_physical, BitField p_modifiers, bool p_pressed, DisplayServer::WindowID p_window) { + Ref ev; + ev.instantiate(); + ev->set_window_id(p_window); + ev->set_echo(false); + ev->set_pressed(p_pressed); + ev->set_keycode(fix_keycode(p_char, p_key)); + if (p_key != Key::SHIFT) { + ev->set_shift_pressed(p_modifiers.has_flag(KeyModifierMask::SHIFT)); + } + if (p_key != Key::CTRL) { + ev->set_ctrl_pressed(p_modifiers.has_flag(KeyModifierMask::CTRL)); + } + if (p_key != Key::ALT) { + ev->set_alt_pressed(p_modifiers.has_flag(KeyModifierMask::ALT)); + } + if (p_key != Key::META) { + ev->set_meta_pressed(p_modifiers.has_flag(KeyModifierMask::META)); + } + ev->set_key_label(p_unshifted); + ev->set_physical_keycode(p_physical); + ev->set_unicode(fix_unicode(p_char)); + perform_event(ev); +} + +// MARK: - + +bool DisplayServerEmbedded::has_feature(Feature p_feature) const { + switch (p_feature) { +#ifndef DISABLE_DEPRECATED + case FEATURE_GLOBAL_MENU: { + return (native_menu && native_menu->has_feature(NativeMenu::FEATURE_GLOBAL_MENU)); + } break; +#endif + case FEATURE_CURSOR_SHAPE: + // case FEATURE_CUSTOM_CURSOR_SHAPE: + // case FEATURE_HIDPI: + // case FEATURE_ICON: + // case FEATURE_IME: + case FEATURE_MOUSE: + // case FEATURE_MOUSE_WARP: + // case FEATURE_NATIVE_DIALOG: + // case FEATURE_NATIVE_ICON: + // case FEATURE_WINDOW_TRANSPARENCY: + //case FEATURE_CLIPBOARD: + //case FEATURE_KEEP_SCREEN_ON: + //case FEATURE_ORIENTATION: + //case FEATURE_VIRTUAL_KEYBOARD: + //case FEATURE_TEXT_TO_SPEECH: + case FEATURE_NATIVE_WINDOWS: + case FEATURE_TOUCHSCREEN: + return true; + default: + return false; + } +} + +String DisplayServerEmbedded::get_name() const { + return "embedded"; +} + +int DisplayServerEmbedded::get_screen_count() const { + return 1; +} + +int DisplayServerEmbedded::get_primary_screen() const { + return 0; +} + +Point2i DisplayServerEmbedded::screen_get_position(int p_screen) const { + return Size2i(); +} + +Size2i DisplayServerEmbedded::screen_get_size(int p_screen) const { + if (screen_get_size_callback.is_valid()) { + return screen_get_size_callback.call(p_screen); + } + return window_get_size(MAIN_WINDOW_ID); +} + +float DisplayServerEmbedded::screen_get_scale(int p_screen) const { + if (screen_get_scale_callback.is_valid()) { + return screen_get_scale_callback.call(p_screen); + } + return DisplayServer::screen_get_scale(p_screen); +} + +Rect2i DisplayServerEmbedded::screen_get_usable_rect(int p_screen) const { + return Rect2i(screen_get_position(p_screen), screen_get_size(p_screen)); +} + +int DisplayServerEmbedded::screen_get_dpi(int p_screen) const { + if (screen_get_dpi_callback.is_valid()) { + return screen_get_dpi_callback.call(p_screen); + } + return 96; +} + +float DisplayServerEmbedded::screen_get_refresh_rate(int p_screen) const { + return -1; +} + +Vector DisplayServerEmbedded::get_window_list() const { + Vector list; + list.push_back(MAIN_WINDOW_ID); + return list; +} + +DisplayServer::WindowID DisplayServerEmbedded::get_window_at_screen_position(const Point2i &p_position) const { + return MAIN_WINDOW_ID; +} + +DisplayServer::WindowID DisplayServerEmbedded::create_native_window(Ref p_native_surface) { + WindowID window_id = window_id_counter++; + window_surfaces[window_id] = p_native_surface; + surface_to_window_id[p_native_surface] = window_id; + +#if defined(RD_ENABLED) + if (rendering_context) { + if (rendering_context->window_create(window_id, p_native_surface) != OK) { + ERR_PRINT(vformat("Failed to create native window.")); + return INVALID_WINDOW_ID; + } + + if (rendering_device) { + rendering_device->screen_create(window_id); + } + return window_id; + } +#endif + +#if defined(GLES3_ENABLED) + if (gl_manager) { + if (gl_manager->window_create(window_id, p_native_surface, 0, 0) != OK) { + ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "GL manager failed to create window"); + } + gl_manager->window_make_current(window_id); + RasterizerGLES3::make_current(false); + return window_id; + } +#endif + ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Cannot create native window with current driver."); +} + +bool DisplayServerEmbedded::is_native_window(DisplayServer::WindowID p_id) { + return true; +} + +void DisplayServerEmbedded::delete_native_window(DisplayServer::WindowID p_id) { +#if defined(RD_ENABLED) + if (rendering_device) { + rendering_device->screen_free(p_id); + } + + if (rendering_context) { + rendering_context->window_destroy(p_id); + } +#endif + +#if defined(GLES3_ENABLED) + if (gl_manager) { + gl_manager->window_destroy(p_id); + } +#endif + + surface_to_window_id.erase(window_surfaces[p_id]); + window_surfaces.erase(p_id); +} + +int64_t DisplayServerEmbedded::window_get_native_handle(HandleType p_handle_type, WindowID p_window) const { + switch (p_handle_type) { +#if defined(GLES3_ENABLED) + case OPENGL_FBO: { + if (gl_manager) { + return gl_manager->window_get_render_target(p_window); + } + return 0; + } + case WINDOW_HANDLE: { + if (gl_manager) { + return (int64_t)gl_manager->window_get_color_texture(p_window); + } + return 0; + } +#endif + default: { + return 0; // Not supported. + } + } +} + +void DisplayServerEmbedded::window_attach_instance_id(ObjectID p_instance, WindowID p_window) { + window_attached_instance_id[p_window] = p_instance; +} + +ObjectID DisplayServerEmbedded::window_get_attached_instance_id(WindowID p_window) const { + return window_attached_instance_id[p_window]; +} + +void DisplayServerEmbedded::window_set_title(const String &p_title, WindowID p_window) { + // Not supported +} + +int DisplayServerEmbedded::window_get_current_screen(WindowID p_window) const { + return SCREEN_OF_MAIN_WINDOW; +} + +void DisplayServerEmbedded::window_set_current_screen(int p_screen, WindowID p_window) { + // Not supported +} + +Point2i DisplayServerEmbedded::window_get_position(WindowID p_window) const { + return Point2i(); +} + +Point2i DisplayServerEmbedded::window_get_position_with_decorations(WindowID p_window) const { + return Point2i(); +} + +void DisplayServerEmbedded::window_set_position(const Point2i &p_position, WindowID p_window) { + // Probably not supported for single window iOS app +} + +void DisplayServerEmbedded::window_set_transient(WindowID p_window, WindowID p_parent) { + // Not supported +} + +void DisplayServerEmbedded::window_set_max_size(const Size2i p_size, WindowID p_window) { + // Not supported +} + +Size2i DisplayServerEmbedded::window_get_max_size(WindowID p_window) const { + return Size2i(); +} + +void DisplayServerEmbedded::window_set_min_size(const Size2i p_size, WindowID p_window) { + // Not supported +} + +Size2i DisplayServerEmbedded::window_get_min_size(WindowID p_window) const { + return Size2i(); +} + +void DisplayServerEmbedded::window_set_size(const Size2i p_size, WindowID p_window) { + window_sizes[p_window] = p_size; +} + +Size2i DisplayServerEmbedded::window_get_size(WindowID p_window) const { +#if defined(RD_ENABLED) + if (rendering_context) { + uint32_t width = 0; + uint32_t height = 0; + rendering_context->window_get_size(p_window, width, height); + return Size2i(width, height); + } +#endif +#if defined(GLES3_ENABLED) + if (gl_manager) { + return gl_manager->window_get_size(p_window); + } +#endif + if (window_sizes.has(p_window)) { + return window_sizes[p_window]; + } + return Size2i(); +} + +Size2i DisplayServerEmbedded::window_get_size_with_decorations(WindowID p_window) const { + return window_get_size(p_window); +} + +void DisplayServerEmbedded::window_set_mode(WindowMode p_mode, WindowID p_window) { + // Not supported +} + +DisplayServer::WindowMode DisplayServerEmbedded::window_get_mode(WindowID p_window) const { + return WindowMode::WINDOW_MODE_FULLSCREEN; +} + +bool DisplayServerEmbedded::window_is_maximize_allowed(WindowID p_window) const { + return false; +} + +void DisplayServerEmbedded::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) { + // Not supported +} + +bool DisplayServerEmbedded::window_get_flag(WindowFlags p_flag, WindowID p_window) const { + return false; +} + +void DisplayServerEmbedded::window_request_attention(WindowID p_window) { + // Not supported +} + +void DisplayServerEmbedded::window_move_to_foreground(WindowID p_window) { + // Not supported +} + +bool DisplayServerEmbedded::window_is_focused(WindowID p_window) const { + return true; +} + +float DisplayServerEmbedded::screen_get_max_scale() const { + return screen_get_scale(SCREEN_OF_MAIN_WINDOW); +} + +bool DisplayServerEmbedded::window_can_draw(WindowID p_window) const { + return true; +} + +bool DisplayServerEmbedded::can_any_window_draw() const { + return true; +} + +bool DisplayServerEmbedded::is_touchscreen_available() const { + return true; +} + +void DisplayServerEmbedded::resize_window(Size2i p_size, WindowID p_id) { + Size2i size = p_size * content_scale; + +#if defined(RD_ENABLED) + if (rendering_context) { + rendering_context->window_set_size(p_id, size.x, size.y); + } +#endif + +#if defined(GLES3_ENABLED) + if (gl_manager) { + gl_manager->window_resize(p_id, p_size.width, p_size.height); + } +#endif + + Variant resize_rect = Rect2i(Point2i(), size); + _window_callback(window_resize_callbacks[p_id], resize_rect); +} + +void DisplayServerEmbedded::set_content_scale(float p_scale) { + content_scale = p_scale; +} + +void DisplayServerEmbedded::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) { + // Not supported +} + +DisplayServer::VSyncMode DisplayServerEmbedded::window_get_vsync_mode(WindowID p_window) const { + return DisplayServer::VSYNC_ENABLED; +} + +void DisplayServerEmbedded::swap_buffers() { +#if defined(GLES3_ENABLED) + if (gl_manager) { + gl_manager->swap_buffers(); + } +#endif +} + +uint64_t DisplayServerEmbedded::get_native_window_id(WindowID p_id) const { +#if defined(GLES3_ENABLED) + if (gl_manager) { + return gl_manager->window_get_render_target(p_id); + } +#endif + return 0; +} + +bool DisplayServerEmbedded::is_rendering_flipped() const { + return false; +} + +DisplayServer::WindowID DisplayServerEmbedded::get_native_surface_window_id(Ref p_native_surface) const { + ERR_FAIL_COND_V(!surface_to_window_id.has(p_native_surface), DisplayServer::INVALID_WINDOW_ID); + return surface_to_window_id[p_native_surface]; +} + +void DisplayServerEmbedded::gl_window_make_current(DisplayServer::WindowID p_window_id) { +#if defined(GLES3_ENABLED) + if (gl_manager) { + gl_manager->window_make_current(p_window_id); + } + current_window = p_window_id; +#endif +} + +void DisplayServerEmbedded::set_host_interface(Ref p_host_interface) { + host_interface = p_host_interface; +} + +DisplayServer::CursorShape DisplayServerEmbedded::cursor_get_shape() const { + if (host_interface.is_valid()) { + return (DisplayServer::CursorShape)host_interface->cursor_get_shape(); + } + + ERR_FAIL_V_MSG(DisplayServer::CursorShape::CURSOR_ARROW, "No host interface set."); +} + +void DisplayServerEmbedded::cursor_set_shape(CursorShape p_shape) { + if (host_interface.is_valid()) { + host_interface->cursor_set_shape((Input::CursorShape)p_shape); + } +} + +void DisplayServerEmbedded::delete_host_interface() { + host_interface = nullptr; +} diff --git a/servers/display_server_embedded.h b/servers/display_server_embedded.h new file mode 100644 index 000000000000..9a6f8bae3fc1 --- /dev/null +++ b/servers/display_server_embedded.h @@ -0,0 +1,237 @@ +/**************************************************************************/ +/* display_server_embedded.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. */ +/**************************************************************************/ + +#pragma once + +#include "core/input/input.h" +#include "servers/display_server.h" + +#if defined(RD_ENABLED) +#include "servers/rendering/renderer_rd/renderer_compositor_rd.h" +#include "servers/rendering/rendering_device.h" +#endif + +#if defined(GLES3_ENABLED) +#include "drivers/gles3/rasterizer_gles3.h" + +#include "servers/rendering/gl_manager.h" +#endif // GLES3_ENABLED + +class DisplayServerEmbedded : public DisplayServer { + GDCLASS(DisplayServerEmbedded, DisplayServer) + + _THREAD_SAFE_CLASS_ + +#if defined(RD_ENABLED) + RenderingContextDriver *rendering_context = nullptr; + RenderingDevice *rendering_device = nullptr; +#endif +#if defined(GLES3_ENABLED) + GLManager *gl_manager = nullptr; +#endif + NativeMenu *native_menu = nullptr; + + DisplayServer::ScreenOrientation screen_orientation; + + HashMap window_attached_instance_id; + + HashMap window_event_callbacks; + HashMap window_resize_callbacks; + HashMap input_event_callbacks; + HashMap input_text_callbacks; + + float content_scale = 1.0f; + + WindowID window_id_counter = MAIN_WINDOW_ID; + + DisplayServer::MouseMode mouse_mode = MOUSE_MODE_VISIBLE; + + void perform_event(const Ref &p_event); + + static Ref native_surface; + HashMap> window_surfaces; + HashMap, WindowID> surface_to_window_id; + HashMap window_sizes; + +#if defined(GLES3_ENABLED) + WindowID current_window = INVALID_WINDOW_ID; +#endif + + Point2i mouse_position; + BitField mouse_button_state; + + static inline Callable screen_get_dpi_callback; + static inline Callable screen_get_size_callback; + static inline Callable screen_get_scale_callback; + + DisplayServerEmbedded(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, Error &r_error); + ~DisplayServerEmbedded(); + +protected: + Ref host_interface; + + static void _bind_methods(); + +public: + String rendering_driver; + + static DisplayServerEmbedded *get_singleton(); + + static void set_native_surface(Ref p_native_handle); + static void set_screen_get_dpi_callback(Callable p_callback); + static void set_screen_get_size_callback(Callable p_callback); + static void set_screen_get_scale_callback(Callable p_callback); + + static void register_embedded_driver(); + static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error); + static Vector get_rendering_drivers_func(); + + // MARK: - Events + + virtual void process_events() override; + + virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override; + virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override; + virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override; + virtual void window_set_input_text_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override; + virtual void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override; + + static void _dispatch_input_events(const Ref &p_event); + void send_input_event(const Ref &p_event, DisplayServer::WindowID p_id = MAIN_WINDOW_ID) const; + void send_input_text(const String &p_text, DisplayServer::WindowID p_id = MAIN_WINDOW_ID) const; + void send_window_event(DisplayServer::WindowEvent p_event, DisplayServer::WindowID p_id = MAIN_WINDOW_ID) const; + void _window_callback(const Callable &p_callable, const Variant &p_arg) const; + + // MARK: - Input + + // MARK: Mouse + virtual void mouse_set_mode(MouseMode p_mode) override; + virtual MouseMode mouse_get_mode() const override; + + virtual Point2i mouse_get_position() const override; + virtual BitField mouse_get_button_state() const override; + + virtual void mouse_button(int p_x, int p_y, MouseButton p_mouse_button_index, bool p_pressed, bool p_double_click, bool p_cancelled, DisplayServer::WindowID p_window) override; + virtual void mouse_motion(int p_prev_x, int p_prev_y, int p_x, int p_y, DisplayServer::WindowID p_window) override; + + // MARK: Touches and Apple Pencil + + virtual void touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_double_click, DisplayServer::WindowID p_window) override; + virtual void touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y, float p_pressure, Vector2 p_tilt, DisplayServer::WindowID p_window) override; + void touches_canceled(int p_idx, DisplayServer::WindowID p_window); + + // MARK: Keyboard + + virtual void key(Key p_key, char32_t p_char, Key p_unshifted, Key p_physical, BitField p_modifiers, bool p_pressed, DisplayServer::WindowID p_window) override; + + // MARK: - + + virtual bool has_feature(Feature p_feature) const override; + virtual String get_name() const override; + + virtual int get_screen_count() const override; + virtual int get_primary_screen() const override; + virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; + virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; + virtual float screen_get_scale(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; + virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; + virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; + virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; + + virtual Vector get_window_list() const override; + + virtual WindowID get_window_at_screen_position(const Point2i &p_position) const override; + + virtual WindowID create_native_window(Ref p_native_window) override; + virtual bool is_native_window(WindowID p_id) override; + virtual void delete_native_window(WindowID p_id) override; + + virtual int64_t window_get_native_handle(HandleType p_handle_type, WindowID p_window = MAIN_WINDOW_ID) const override; + + virtual void window_attach_instance_id(ObjectID p_instance, WindowID p_window = MAIN_WINDOW_ID) override; + virtual ObjectID window_get_attached_instance_id(WindowID p_window = MAIN_WINDOW_ID) const override; + + virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID) override; + + virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const override; + virtual void window_set_current_screen(int p_screen, WindowID p_window = MAIN_WINDOW_ID) override; + + virtual Point2i window_get_position(WindowID p_window = MAIN_WINDOW_ID) const override; + virtual Point2i window_get_position_with_decorations(WindowID p_window = MAIN_WINDOW_ID) const override; + virtual void window_set_position(const Point2i &p_position, WindowID p_window = MAIN_WINDOW_ID) override; + + virtual void window_set_transient(WindowID p_window, WindowID p_parent) override; + + virtual void window_set_max_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) override; + virtual Size2i window_get_max_size(WindowID p_window = MAIN_WINDOW_ID) const override; + + virtual void window_set_min_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) override; + virtual Size2i window_get_min_size(WindowID p_window = MAIN_WINDOW_ID) const override; + + virtual void window_set_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) override; + virtual Size2i window_get_size(WindowID p_window = MAIN_WINDOW_ID) const override; + virtual Size2i window_get_size_with_decorations(WindowID p_window = MAIN_WINDOW_ID) const override; + + virtual void window_set_mode(WindowMode p_mode, WindowID p_window = MAIN_WINDOW_ID) override; + virtual WindowMode window_get_mode(WindowID p_window = MAIN_WINDOW_ID) const override; + + virtual bool window_is_maximize_allowed(WindowID p_window = MAIN_WINDOW_ID) const override; + + virtual void window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window = MAIN_WINDOW_ID) override; + virtual bool window_get_flag(WindowFlags p_flag, WindowID p_window = MAIN_WINDOW_ID) const override; + + virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) override; + 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 float screen_get_max_scale() const override; + + virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const override; + + virtual bool can_any_window_draw() const override; + + virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID) override; + virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_vsync_mode) const override; + + virtual bool is_touchscreen_available() const override; + + void resize_window(Size2i size, WindowID p_id); + void set_content_scale(float p_scale); + virtual void swap_buffers() override; + virtual uint64_t get_native_window_id(WindowID p_id = MAIN_WINDOW_ID) const override; + virtual bool is_rendering_flipped() const override; + virtual WindowID get_native_surface_window_id(Ref p_native_surface) const; + virtual void gl_window_make_current(DisplayServer::WindowID p_window_id) override; + + void set_host_interface(Ref p_host_interface); + virtual CursorShape cursor_get_shape() const override; + virtual void cursor_set_shape(CursorShape p_shape) override; + void delete_host_interface(); +}; diff --git a/servers/display_server_embedded_host_interface.cpp b/servers/display_server_embedded_host_interface.cpp new file mode 100644 index 000000000000..74d85745009e --- /dev/null +++ b/servers/display_server_embedded_host_interface.cpp @@ -0,0 +1,46 @@ +/**************************************************************************/ +/* display_server_embedded_host_interface.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 "servers/display_server_embedded_host_interface.h" + +void DisplayServerEmbeddedHostInterface::_bind_methods() { + GDVIRTUAL_BIND(_cursor_get_shape); + GDVIRTUAL_BIND(_cursor_set_shape, "shape"); +} + +Input::CursorShape DisplayServerEmbeddedHostInterface::cursor_get_shape() const { + Input::CursorShape cursor_shape; + GDVIRTUAL_CALL(_cursor_get_shape, cursor_shape); + return cursor_shape; +} + +void DisplayServerEmbeddedHostInterface::cursor_set_shape(Input::CursorShape p_shape) { + GDVIRTUAL_CALL(_cursor_set_shape, p_shape); +} diff --git a/drivers/apple_embedded/rendering_context_driver_vulkan_apple_embedded.h b/servers/display_server_embedded_host_interface.h similarity index 78% rename from drivers/apple_embedded/rendering_context_driver_vulkan_apple_embedded.h rename to servers/display_server_embedded_host_interface.h index 8e12bc163a64..0a224e05111b 100644 --- a/drivers/apple_embedded/rendering_context_driver_vulkan_apple_embedded.h +++ b/servers/display_server_embedded_host_interface.h @@ -1,5 +1,5 @@ /**************************************************************************/ -/* rendering_context_driver_vulkan_apple_embedded.h */ +/* display_server_embedded_host_interface.h */ /**************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -30,26 +30,19 @@ #pragma once -#ifdef VULKAN_ENABLED +#include "core/input/input.h" +#include "core/object/ref_counted.h" -#include "drivers/vulkan/rendering_context_driver_vulkan.h" - -#import - -class RenderingContextDriverVulkanAppleEmbedded : public RenderingContextDriverVulkan { -private: - virtual const char *_get_platform_surface_extension() const override final; +class DisplayServerEmbeddedHostInterface : public RefCounted { + GDCLASS(DisplayServerEmbeddedHostInterface, RefCounted); protected: - SurfaceID surface_create(const void *p_platform_data) override final; + static void _bind_methods(); public: - struct WindowPlatformData { - CAMetalLayer *const *layer_ptr; - }; + GDVIRTUAL0RC(Input::CursorShape, _cursor_get_shape); + GDVIRTUAL1(_cursor_set_shape, Input::CursorShape); - RenderingContextDriverVulkanAppleEmbedded(); - ~RenderingContextDriverVulkanAppleEmbedded(); + virtual Input::CursorShape cursor_get_shape() const; + virtual void cursor_set_shape(Input::CursorShape p_shape); }; - -#endif // VULKAN_ENABLED diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index 0029ef5fe626..4a1c6793ab76 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -58,8 +58,10 @@ #include "debugger/servers_debugger.h" #include "display/native_menu.h" #include "display_server.h" +#include "display_server_embedded.h" #include "movie_writer/movie_writer.h" #include "movie_writer/movie_writer_pngwav.h" +#include "rendering/renderer_compositor.h" #include "rendering/renderer_rd/framebuffer_cache_rd.h" #include "rendering/renderer_rd/storage_rd/render_data_rd.h" #include "rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h" @@ -67,11 +69,14 @@ #include "rendering/renderer_rd/uniform_set_cache_rd.h" #include "rendering/rendering_device.h" #include "rendering/rendering_device_binds.h" +#include "rendering/rendering_native_surface.h" +#include "rendering/rendering_native_surface_external_target.h" #include "rendering/shader_include_db.h" #include "rendering/storage/render_data.h" #include "rendering/storage/render_scene_buffers.h" #include "rendering/storage/render_scene_data.h" #include "rendering_server.h" +#include "servers/display_server_embedded_host_interface.h" #include "servers/rendering/shader_types.h" #include "text/text_server_dummy.h" #include "text/text_server_extension.h" @@ -136,6 +141,21 @@ static bool has_server_feature_callback(const String &p_feature) { static MovieWriterPNGWAV *writer_pngwav = nullptr; +void register_core_server_types() { + OS::get_singleton()->benchmark_begin_measure("Servers", "Register Core Extensions"); + GDREGISTER_ABSTRACT_CLASS(RenderingNativeSurface); + GDREGISTER_CLASS(DisplayServerEmbeddedHostInterface); + GDREGISTER_ABSTRACT_CLASS(DisplayServer); +#ifdef EXTERNAL_TARGET_ENABLED + GDREGISTER_CLASS(RenderingNativeSurfaceExternalTarget); +#endif + GDREGISTER_ABSTRACT_CLASS(DisplayServerEmbedded); + OS::get_singleton()->benchmark_end_measure("Servers", "Register Core Extensions"); +} + +void unregister_core_server_types() { +} + void register_server_types() { OS::get_singleton()->benchmark_begin_measure("Servers", "Register Extensions"); @@ -153,7 +173,6 @@ void register_server_types() { OS::get_singleton()->set_has_server_feature_callback(has_server_feature_callback); - GDREGISTER_ABSTRACT_CLASS(DisplayServer); GDREGISTER_ABSTRACT_CLASS(RenderingServer); GDREGISTER_CLASS(AudioServer); diff --git a/servers/register_server_types.h b/servers/register_server_types.h index c78f9bf85a96..59ffbfa72c97 100644 --- a/servers/register_server_types.h +++ b/servers/register_server_types.h @@ -30,6 +30,9 @@ #pragma once +void register_core_server_types(); +void unregister_core_server_types(); + void register_server_types(); void unregister_server_types(); diff --git a/servers/rendering/dummy/rasterizer_dummy.h b/servers/rendering/dummy/rasterizer_dummy.h index 93f0b7313d29..8b98720c81c1 100644 --- a/servers/rendering/dummy/rasterizer_dummy.h +++ b/servers/rendering/dummy/rasterizer_dummy.h @@ -76,7 +76,7 @@ class RasterizerDummy : public RendererCompositor { RendererCanvasRender *get_canvas() override { return &canvas; } RendererSceneRender *get_scene() override { return &scene; } - void set_boot_image(const Ref &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true) override {} + void set_boot_image(const Ref &p_image, const Color &p_color, bool p_scale, DisplayServer::WindowID p_screen, bool p_use_filter = true) override {} void initialize() override {} void begin_frame(double frame_step) override { diff --git a/servers/rendering/dummy/storage/texture_storage.h b/servers/rendering/dummy/storage/texture_storage.h index afda5e054c7a..73d12c4593ee 100644 --- a/servers/rendering/dummy/storage/texture_storage.h +++ b/servers/rendering/dummy/storage/texture_storage.h @@ -169,7 +169,7 @@ class TextureStorage : public RendererTextureStorage { virtual Size2i render_target_get_size(RID p_render_target) const override { return Size2i(); } virtual void render_target_set_transparent(RID p_render_target, bool p_is_transparent) override {} virtual bool render_target_get_transparent(RID p_render_target) const override { return false; } - virtual void render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) override {} + virtual void render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen, DisplayServer::WindowID p_direct_to_screen_id) override {} virtual bool render_target_get_direct_to_screen(RID p_render_target) const override { return false; } virtual bool render_target_was_used(RID p_render_target) const override { return false; } virtual void render_target_set_as_unused(RID p_render_target) override {} diff --git a/servers/rendering/gl_manager.h b/servers/rendering/gl_manager.h new file mode 100644 index 000000000000..3de1bf6bdb50 --- /dev/null +++ b/servers/rendering/gl_manager.h @@ -0,0 +1,63 @@ +/**************************************************************************/ +/* gl_manager.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. */ +/**************************************************************************/ + +#pragma once + +#if defined(GLES3_ENABLED) +// These must come first to avoid windows.h mess. +#include "platform_gl.h" +#endif + +#include "core/error/error_macros.h" +#include "servers/display_server.h" +#include "servers/rendering/rendering_native_surface.h" + +class GLManager { +public: + virtual Error open_display(void *p_display) = 0; + virtual Error window_create(DisplayServer::WindowID p_window_id, Ref p_native_surface, int p_width, int p_height) = 0; + virtual void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) = 0; + virtual void window_destroy(DisplayServer::WindowID p_window_id) = 0; + virtual Size2i window_get_size(DisplayServer::WindowID p_id) = 0; + virtual int window_get_render_target(DisplayServer::WindowID p_window_id) const = 0; + virtual int window_get_color_texture(DisplayServer::WindowID p_id) const = 0; + virtual void release_current() = 0; + virtual void swap_buffers() = 0; + + virtual void window_make_current(DisplayServer::WindowID p_window_id) = 0; + + virtual void set_use_vsync(bool p_use) = 0; + virtual bool is_using_vsync() const = 0; + + virtual Error initialize(void *p_native_display = nullptr) = 0; + + GLManager() {} + virtual ~GLManager() {} +}; diff --git a/servers/rendering/renderer_compositor.h b/servers/rendering/renderer_compositor.h index c5819bb2c64c..ad0e1671c652 100644 --- a/servers/rendering/renderer_compositor.h +++ b/servers/rendering/renderer_compositor.h @@ -87,7 +87,7 @@ class RendererCompositor { virtual RendererCanvasRender *get_canvas() = 0; virtual RendererSceneRender *get_scene() = 0; - virtual void set_boot_image(const Ref &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true) = 0; + virtual void set_boot_image(const Ref &p_image, const Color &p_color, bool p_scale, DisplayServer::WindowID p_screen, bool p_use_filter = true) = 0; virtual void initialize() = 0; virtual void begin_frame(double frame_step) = 0; diff --git a/servers/rendering/renderer_rd/effects/metal_fx.h b/servers/rendering/renderer_rd/effects/metal_fx.h index b2a68aa1f95d..53d487685d63 100644 --- a/servers/rendering/renderer_rd/effects/metal_fx.h +++ b/servers/rendering/renderer_rd/effects/metal_fx.h @@ -30,7 +30,7 @@ #pragma once -#if defined(METAL_ENABLED) && !defined(VISIONOS_ENABLED) +#if defined(METAL_ENABLED) && !defined(VISIONOS_ENABLED) && !defined(IOS_SIMULATOR) #define METAL_MFXTEMPORAL_ENABLED #endif diff --git a/servers/rendering/renderer_rd/effects/metal_fx.mm b/servers/rendering/renderer_rd/effects/metal_fx.mm index 0f6152d5261e..58c7aca60317 100644 --- a/servers/rendering/renderer_rd/effects/metal_fx.mm +++ b/servers/rendering/renderer_rd/effects/metal_fx.mm @@ -28,6 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ +#if !defined(IOS_SIMULATOR) + #import "metal_fx.h" #import "../storage_rd/render_scene_buffers_rd.h" @@ -223,3 +225,4 @@ } #endif +#endif 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 6496c8bbfa92..28f9b185f268 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -5049,8 +5049,10 @@ RenderForwardClustered::RenderForwardClustered() { ss_effects = memnew(RendererRD::SSEffects); #ifdef METAL_MFXTEMPORAL_ENABLED motion_vectors_store = memnew(RendererRD::MotionVectorsStore); +#if !defined(IOS_SIMULATOR) mfx_temporal_effect = memnew(RendererRD::MFXTemporalEffect); #endif +#endif } RenderForwardClustered::~RenderForwardClustered() { @@ -5113,4 +5115,7 @@ RenderForwardClustered::~RenderForwardClustered() { RD::get_singleton()->free(sdfgi_framebuffer_size_cache.begin()->value); sdfgi_framebuffer_size_cache.remove(sdfgi_framebuffer_size_cache.begin()); } + + ERR_FAIL_COND(singleton != this); + singleton = nullptr; } 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 1c0a803c1a5e..5de329996035 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h @@ -33,7 +33,7 @@ #include "core/templates/paged_allocator.h" #include "servers/rendering/renderer_rd/cluster_builder_rd.h" #include "servers/rendering/renderer_rd/effects/fsr2.h" -#ifdef METAL_ENABLED +#if defined(METAL_ENABLED) && !defined(IOS_SIMULATOR) #include "servers/rendering/renderer_rd/effects/metal_fx.h" #endif #include "servers/rendering/renderer_rd/effects/motion_vectors_store.h" 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 8154f6ab51d9..572db67011e5 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 @@ -616,6 +616,9 @@ SceneShaderForwardClustered::~SceneShaderForwardClustered() { material_storage->material_free(overdraw_material); material_storage->material_free(default_material); material_storage->material_free(debug_shadow_splits_material); + + ERR_FAIL_COND(singleton != this); + singleton = nullptr; } void SceneShaderForwardClustered::init(const String p_defines) { 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 7cce88a5b887..f17c2ff72c6a 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -3401,4 +3401,7 @@ RenderForwardMobile::~RenderForwardMobile() { RD::get_singleton()->free(scene_state.lightmap_capture_buffer); memdelete_arr(scene_state.lightmap_captures); } + + ERR_FAIL_COND(singleton != this); + singleton = nullptr; } 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 cc0f406b6d17..95d93c3e8f92 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 @@ -963,4 +963,7 @@ SceneShaderForwardMobile::~SceneShaderForwardMobile() { material_storage->material_free(overdraw_material); material_storage->material_free(default_material); material_storage->material_free(debug_shadow_splits_material); + + ERR_FAIL_COND(singleton != this); + singleton = nullptr; } diff --git a/servers/rendering/renderer_rd/framebuffer_cache_rd.cpp b/servers/rendering/renderer_rd/framebuffer_cache_rd.cpp index ec037b71faf8..5dce17eff780 100644 --- a/servers/rendering/renderer_rd/framebuffer_cache_rd.cpp +++ b/servers/rendering/renderer_rd/framebuffer_cache_rd.cpp @@ -84,4 +84,6 @@ FramebufferCacheRD::~FramebufferCacheRD() { if (cache_instances_used > 0) { ERR_PRINT("At exit: " + itos(cache_instances_used) + " framebuffer cache instance(s) still in use."); } + ERR_FAIL_COND(singleton != this); + singleton = nullptr; } diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp index 8642d71789c3..00398667ac21 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp @@ -185,12 +185,12 @@ void RendererCompositorRD::finalize() { RD::get_singleton()->free(blit.sampler); } -void RendererCompositorRD::set_boot_image(const Ref &p_image, const Color &p_color, bool p_scale, bool p_use_filter) { +void RendererCompositorRD::set_boot_image(const Ref &p_image, const Color &p_color, bool p_scale, DisplayServer::WindowID p_screen, bool p_use_filter) { if (p_image.is_null() || p_image->is_empty()) { return; } - Error err = RD::get_singleton()->screen_prepare_for_drawing(DisplayServer::MAIN_WINDOW_ID); + Error err = RD::get_singleton()->screen_prepare_for_drawing(p_screen); if (err != OK) { // Window is minimized and does not have valid swapchain, skip drawing without printing errors. return; @@ -218,7 +218,7 @@ void RendererCompositorRD::set_boot_image(const Ref &p_image, const Color uset = RD::get_singleton()->uniform_set_create(uniforms, blit.shader.version_get_shader(blit.shader_version, BLIT_MODE_NORMAL), 0); } - Size2 window_size = DisplayServer::get_singleton()->window_get_size(); + Size2 window_size = DisplayServer::get_singleton()->window_get_size(p_screen); Rect2 imgrect(0, 0, p_image->get_width(), p_image->get_height()); Rect2 screenrect; @@ -232,7 +232,7 @@ void RendererCompositorRD::set_boot_image(const Ref &p_image, const Color screenrect.position /= window_size; screenrect.size /= window_size; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin_for_screen(DisplayServer::MAIN_WINDOW_ID, p_color); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin_for_screen(p_screen, p_color); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blit.pipelines[BLIT_MODE_NORMAL_ALPHA]); RD::get_singleton()->draw_list_bind_index_array(draw_list, blit.array); diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h index dd9e420db037..4ebfc385ea71 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.h +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h @@ -119,7 +119,7 @@ class RendererCompositorRD : public RendererCompositor { RendererCanvasRender *get_canvas() { return canvas; } RendererSceneRender *get_scene() { return scene; } - void set_boot_image(const Ref &p_image, const Color &p_color, bool p_scale, bool p_use_filter); + void set_boot_image(const Ref &p_image, const Color &p_color, bool p_scale, DisplayServer::WindowID p_screen, bool p_use_filter); void initialize(); void begin_frame(double frame_step); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index cdcca5042291..7a44993f70a1 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -470,7 +470,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende if (scale_mode == RS::VIEWPORT_SCALING_3D_MODE_FSR) { spatial_upscaler = fsr; } else if (scale_mode == RS::VIEWPORT_SCALING_3D_MODE_METALFX_SPATIAL) { -#if METAL_ENABLED +#if defined(METAL_ENABLED) && !defined(IOS_SIMULATOR) spatial_upscaler = mfx_spatial; #endif } @@ -1719,7 +1719,7 @@ void RendererSceneRenderRD::init() { if (can_use_storage) { fsr = memnew(RendererRD::FSR); } -#ifdef METAL_ENABLED +#if defined(METAL_ENABLED) && !defined(IOS_SIMULATOR) mfx_spatial = memnew(RendererRD::MFXSpatialEffect); #endif resolve_effects = memnew(RendererRD::Resolve(!can_use_storage)); @@ -1754,7 +1754,7 @@ RendererSceneRenderRD::~RendererSceneRenderRD() { if (fsr) { memdelete(fsr); } -#ifdef METAL_ENABLED +#if defined(METAL_ENABLED) && !defined(IOS_SIMULATOR) if (mfx_spatial) { memdelete(mfx_spatial); } @@ -1783,4 +1783,7 @@ RendererSceneRenderRD::~RendererSceneRenderRD() { RSG::light_storage->directional_shadow_atlas_set_size(0); cull_argument.reset(); //avoid exit error + + ERR_FAIL_COND(singleton != this); + singleton = nullptr; } diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index c6e471e3e813..6d613cced91e 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -36,7 +36,7 @@ #include "servers/rendering/renderer_rd/effects/debug_effects.h" #include "servers/rendering/renderer_rd/effects/fsr.h" #include "servers/rendering/renderer_rd/effects/luminance.h" -#ifdef METAL_ENABLED +#if defined(METAL_ENABLED) && !defined(IOS_SIMULATOR) #include "servers/rendering/renderer_rd/effects/metal_fx.h" #endif #include "servers/rendering/renderer_rd/effects/resolve.h" diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp index dc1474a4c148..0fd77cf8cd13 100644 --- a/servers/rendering/renderer_rd/shader_rd.cpp +++ b/servers/rendering/renderer_rd/shader_rd.cpp @@ -222,6 +222,9 @@ void ShaderRD::_build_variant_code(StringBuilder &builder, uint32_t p_variant, c for (const StageTemplate::Chunk &chunk : p_template.chunks) { switch (chunk.type) { case StageTemplate::Chunk::TYPE_VERSION_DEFINES: { +#if defined(METAL_ENABLED) && defined(IOS_SIMULATOR) + builder.append("#define SIMULATE_CUBEMAP_ARRAYS\n"); +#endif builder.append("\n"); //make sure defines begin at newline builder.append(general_defines.get_data()); builder.append(variant_defines[p_variant].text.get_data()); diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl index 1b1c67f4a00a..d3a14895f8fc 100644 --- a/servers/rendering/renderer_rd/shaders/canvas.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas.glsl @@ -4,6 +4,8 @@ #VERSION_DEFINES +#include "metal_simulator_inc.glsl" + #ifdef USE_ATTRIBUTES layout(location = 0) in vec2 vertex_attrib; layout(location = 3) in vec4 color_attrib; @@ -234,6 +236,8 @@ void main() { #VERSION_DEFINES +#include "metal_simulator_inc.glsl" + #include "canvas_uniforms_inc.glsl" #ifndef USE_ATTRIBUTES diff --git a/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl b/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl index 0fafc7d4869b..b349ed01607a 100644 --- a/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl @@ -4,6 +4,8 @@ #VERSION_DEFINES +#include "metal_simulator_inc.glsl" + layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; layout(r8, set = 0, binding = 1) uniform restrict readonly image2D src_pixels; diff --git a/servers/rendering/renderer_rd/shaders/effects/copy.glsl b/servers/rendering/renderer_rd/shaders/effects/copy.glsl index debf6b736739..411b4ddaf4b2 100644 --- a/servers/rendering/renderer_rd/shaders/effects/copy.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/copy.glsl @@ -4,6 +4,8 @@ #VERSION_DEFINES +#include "../metal_simulator_inc.glsl" + layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; #define FLAG_HORIZONTAL (1 << 0) @@ -41,7 +43,7 @@ layout(push_constant, std430) uniform Params { params; #ifdef MODE_CUBEMAP_ARRAY_TO_PANORAMA -layout(set = 0, binding = 0) uniform samplerCubeArray source_color; +layout(set = 0, binding = 0) uniform samplerCubeArrayFix source_color; #elif defined(MODE_CUBEMAP_TO_PANORAMA) layout(set = 0, binding = 0) uniform samplerCube source_color; #elif !defined(MODE_SET_COLOR) @@ -95,10 +97,17 @@ void main() { vec2 quad_center_uv = clamp(vec2(params.section.xy + gl_GlobalInvocationID.xy + gl_LocalInvocationID.xy - 3.5) / params.section.zw, vec2(0.5 / params.section.zw), vec2(1.0 - 1.5 / params.section.zw)); uint dest_index = gl_LocalInvocationID.x * 2 + gl_LocalInvocationID.y * 2 * 16; +#ifdef MODE_CUBEMAP_ARRAY_TO_PANORAMA + local_cache[dest_index] = textureLodFix(source_color, quad_center_uv, 0); + local_cache[dest_index + 1] = textureLodFix(source_color, quad_center_uv + vec2(1.0 / params.section.z, 0.0), 0); + local_cache[dest_index + 16] = textureLodFix(source_color, quad_center_uv + vec2(0.0, 1.0 / params.section.w), 0); + local_cache[dest_index + 16 + 1] = textureLodFix(source_color, quad_center_uv + vec2(1.0 / params.section.zw), 0); +#else local_cache[dest_index] = textureLod(source_color, quad_center_uv, 0); local_cache[dest_index + 1] = textureLod(source_color, quad_center_uv + vec2(1.0 / params.section.z, 0.0), 0); local_cache[dest_index + 16] = textureLod(source_color, quad_center_uv + vec2(0.0, 1.0 / params.section.w), 0); local_cache[dest_index + 16 + 1] = textureLod(source_color, quad_center_uv + vec2(1.0 / params.section.zw), 0); +#endif #ifdef MODE_GLOW if (bool(params.flags & FLAG_GLOW_FIRST_PASS)) { @@ -208,7 +217,11 @@ void main() { if (bool(params.flags & FLAG_FLIP_Y)) { uv.y = 1.0 - uv.y; } +#ifdef MODE_CUBEMAP_ARRAY_TO_PANORAMA + color = textureLodFix(source_color, uv, 0.0); +#else color = textureLod(source_color, uv, 0.0); +#endif } else { color = texelFetch(source_color, pos + params.section.xy, 0); @@ -273,6 +286,8 @@ void main() { #ifdef MODE_CUBEMAP_TO_PANORAMA vec4 color = textureLod(source_color, normal, params.camera_z_far); //the biggest the lod the least the acne +#elif defined(MODE_CUBEMAP_ARRAY_TO_PANORAMA) + vec4 color = textureLodFix(source_color, vec4(normal, params.camera_z_far), 0.0); //the biggest the lod the least the acne #else vec4 color = textureLod(source_color, vec4(normal, params.camera_z_far), 0.0); //the biggest the lod the least the acne #endif diff --git a/servers/rendering/renderer_rd/shaders/environment/sdfgi_integrate.glsl b/servers/rendering/renderer_rd/shaders/environment/sdfgi_integrate.glsl index aaaa7dfb4318..4f650e54c19e 100644 --- a/servers/rendering/renderer_rd/shaders/environment/sdfgi_integrate.glsl +++ b/servers/rendering/renderer_rd/shaders/environment/sdfgi_integrate.glsl @@ -4,6 +4,8 @@ #VERSION_DEFINES +#include "../metal_simulator_inc.glsl" + layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; #define MAX_CASCADES 8 @@ -41,7 +43,7 @@ layout(rgba32i, set = 0, binding = 13) uniform restrict iimage2D lightprobe_aver layout(rgba16f, set = 0, binding = 14) uniform restrict writeonly image2DArray lightprobe_ambient_texture; #ifdef USE_CUBEMAP_ARRAY -layout(set = 1, binding = 0) uniform textureCubeArray sky_irradiance; +layout(set = 1, binding = 0) uniform textureCubeArrayFix sky_irradiance; #else layout(set = 1, binding = 0) uniform textureCube sky_irradiance; #endif @@ -272,7 +274,7 @@ void main() { vec3 sky_dir = cross(sky_quat.xyz, ray_dir); sky_dir = ray_dir + ((sky_dir * sky_quat.w) + cross(sky_quat.xyz, sky_dir)) * 2.0; #ifdef USE_CUBEMAP_ARRAY - light.rgb = textureLod(samplerCubeArray(sky_irradiance, linear_sampler_mipmaps), vec4(sky_dir, 0.0), 2.0).rgb; // Use second mipmap because we don't usually throw a lot of rays, so this compensates. + light.rgb = textureLodFix(sky_irradiance, linear_sampler_mipmaps, vec4(sky_dir, 0.0), 2.0).rgb; // Use second mipmap because we don't usually throw a lot of rays, so this compensates. #else light.rgb = textureLod(samplerCube(sky_irradiance, linear_sampler_mipmaps), sky_dir, 2.0).rgb; // Use second mipmap because we don't usually throw a lot of rays, so this compensates. #endif diff --git a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl index 47c991292f37..034574658fc9 100644 --- a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl +++ b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl @@ -16,6 +16,7 @@ layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; #include "../cluster_data_inc.glsl" #include "../light_data_inc.glsl" +#include "../metal_simulator_inc.glsl" #define M_PI 3.14159265359 @@ -202,7 +203,7 @@ layout(r32ui, set = 0, binding = 18) uniform uimage3D emissive_only_map; #endif #ifdef USE_RADIANCE_CUBEMAP_ARRAY -layout(set = 0, binding = 19) uniform textureCubeArray sky_texture; +layout(set = 0, binding = 19) uniform textureCubeArrayFix sky_texture; #else layout(set = 0, binding = 19) uniform textureCube sky_texture; #endif @@ -430,8 +431,8 @@ void main() { float mip_bias = 2.0 + total_density * (MAX_SKY_LOD - 2.0); // Not physically based, but looks nice vec3 scatter_direction = (params.radiance_inverse_xform * normalize(view_pos)) * sign(params.phase_g); #ifdef USE_RADIANCE_CUBEMAP_ARRAY - isotropic = texture(samplerCubeArray(sky_texture, linear_sampler_with_mipmaps), vec4(0.0, 1.0, 0.0, mip_bias)).rgb; - anisotropic = texture(samplerCubeArray(sky_texture, linear_sampler_with_mipmaps), vec4(scatter_direction, mip_bias)).rgb; + isotropic = textureFix(sky_texture, linear_sampler_with_mipmaps, vec4(0.0, 1.0, 0.0, mip_bias)).rgb; + anisotropic = textureFix(sky_texture, linear_sampler_with_mipmaps, vec4(scatter_direction, mip_bias)).rgb; #else isotropic = textureLod(samplerCube(sky_texture, linear_sampler_with_mipmaps), vec3(0.0, 1.0, 0.0), mip_bias).rgb; anisotropic = textureLod(samplerCube(sky_texture, linear_sampler_with_mipmaps), vec3(scatter_direction), mip_bias).rgb; diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl index 6b54067568f4..73a11b647002 100644 --- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl @@ -7,6 +7,7 @@ /* Include half precision types. */ #include "../half_inc.glsl" +#include "../metal_simulator_inc.glsl" #include "scene_forward_clustered_inc.glsl" #define SHADER_IS_SRGB false @@ -821,6 +822,8 @@ void main() { #VERSION_DEFINES +#include "../metal_simulator_inc.glsl" + #define SHADER_IS_SRGB false #define SHADER_SPACE_FAR 0.0 @@ -1054,8 +1057,8 @@ vec4 fog_process(vec3 vertex) { #ifdef USE_RADIANCE_CUBEMAP_ARRAY float lod, blend; blend = modf(mip_level * MAX_ROUGHNESS_LOD, lod); - sky_fog_color = texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(cube_view, lod)).rgb; - sky_fog_color = mix(sky_fog_color, texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(cube_view, lod + 1)).rgb, blend); + sky_fog_color = textureFix(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP, vec4(cube_view, lod)).rgb; + sky_fog_color = mix(sky_fog_color, textureFix(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP, vec4(cube_view, lod + 1)).rgb, blend); #else sky_fog_color = textureLod(samplerCube(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), cube_view, mip_level * MAX_ROUGHNESS_LOD).rgb; #endif //USE_RADIANCE_CUBEMAP_ARRAY @@ -1620,8 +1623,8 @@ void fragment_shader(in SceneData scene_data) { float lod, blend; blend = modf(sqrt(roughness) * MAX_ROUGHNESS_LOD, lod); - indirect_specular_light = texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod)).rgb; - indirect_specular_light = mix(indirect_specular_light, texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod + 1)).rgb, blend); + indirect_specular_light = textureFix(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP, vec4(ref_vec, lod)).rgb; + indirect_specular_light = mix(indirect_specular_light, textureFix(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP, vec4(ref_vec, lod + 1)).rgb, blend); #else indirect_specular_light = textureLod(samplerCube(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ref_vec, sqrt(roughness) * MAX_ROUGHNESS_LOD).rgb; @@ -1644,7 +1647,7 @@ void fragment_shader(in SceneData scene_data) { if (bool(scene_data.flags & SCENE_DATA_FLAGS_USE_AMBIENT_CUBEMAP)) { vec3 ambient_dir = scene_data.radiance_inverse_xform * indirect_normal; #ifdef USE_RADIANCE_CUBEMAP_ARRAY - vec3 cubemap_ambient = texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ambient_dir, MAX_ROUGHNESS_LOD)).rgb; + vec3 cubemap_ambient = textureFix(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP, vec4(ambient_dir, MAX_ROUGHNESS_LOD)).rgb; #else vec3 cubemap_ambient = textureLod(samplerCube(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ambient_dir, MAX_ROUGHNESS_LOD).rgb; #endif //USE_RADIANCE_CUBEMAP_ARRAY @@ -1676,8 +1679,8 @@ void fragment_shader(in SceneData scene_data) { float lod, blend; blend = modf(roughness_lod, lod); - vec3 clearcoat_light = texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod)).rgb; - clearcoat_light = mix(clearcoat_light, texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod + 1)).rgb, blend); + vec3 clearcoat_light = textureFix(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP, vec4(ref_vec, lod)).rgb; + clearcoat_light = mix(clearcoat_light, textureFix(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP, vec4(ref_vec, lod + 1)).rgb, blend); #else vec3 clearcoat_light = textureLod(samplerCube(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ref_vec, roughness_lod).rgb; diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl index 328e2f9263bb..e80d41163dd4 100644 --- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl @@ -10,6 +10,7 @@ #include "../cluster_data_inc.glsl" #include "../decal_data_inc.glsl" +#include "../metal_simulator_inc.glsl" #include "../scene_data_inc.glsl" #if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(MODE_RENDER_SDF) || defined(MODE_RENDER_NORMAL_ROUGHNESS) || defined(MODE_RENDER_VOXEL_GI) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(BENT_NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) @@ -332,7 +333,7 @@ instances; #ifdef USE_RADIANCE_CUBEMAP_ARRAY -layout(set = 1, binding = 3) uniform textureCubeArray radiance_cubemap; +layout(set = 1, binding = 3) uniform textureCubeArrayFix radiance_cubemap; #else @@ -340,7 +341,7 @@ layout(set = 1, binding = 3) uniform textureCube radiance_cubemap; #endif -layout(set = 1, binding = 4) uniform textureCubeArray reflection_atlas; +layout(set = 1, binding = 4) uniform textureCubeArrayFix reflection_atlas; layout(set = 1, binding = 5) uniform texture2D shadow_atlas; diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl index df41def54d11..2f11f5ee2307 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl @@ -10,6 +10,8 @@ /* Include our forward mobile UBOs definitions etc. */ #include "scene_forward_mobile_inc.glsl" +#include "../metal_simulator_inc.glsl" + #define SHADER_IS_SRGB false #define SHADER_SPACE_FAR 0.0 @@ -779,6 +781,8 @@ void main() { #VERSION_DEFINES +#include "../metal_simulator_inc.glsl" + #define SHADER_IS_SRGB false #define SHADER_SPACE_FAR 0.0 @@ -1002,8 +1006,8 @@ hvec4 fog_process(vec3 vertex) { #ifdef USE_RADIANCE_CUBEMAP_ARRAY float lod, blend; blend = modf(mip_level * MAX_ROUGHNESS_LOD, lod); - sky_fog_color = texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(cube_view, lod)).rgb; - sky_fog_color = mix(sky_fog_color, texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(cube_view, lod + 1)).rgb, blend); + sky_fog_color = textureFix(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP, vec4(cube_view, lod)).rgb; + sky_fog_color = mix(sky_fog_color, textureFix(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP, vec4(cube_view, lod + 1)).rgb, blend); #else sky_fog_color = textureLod(samplerCube(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), cube_view, mip_level * MAX_ROUGHNESS_LOD).rgb; #endif //USE_RADIANCE_CUBEMAP_ARRAY @@ -1532,8 +1536,8 @@ void main() { float lod; half blend = half(modf(float(sqrt(roughness) * half(MAX_ROUGHNESS_LOD)), lod)); - hvec3 indirect_sample_a = hvec3(texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(vec3(ref_vec), float(lod))).rgb); - hvec3 indirect_sample_b = hvec3(texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(vec3(ref_vec), float(lod) + 1.0)).rgb); + hvec3 indirect_sample_a = hvec3(textureFix(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP, vec4(vec3(ref_vec), float(lod))).rgb); + hvec3 indirect_sample_b = hvec3(textureFix(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP, vec4(vec3(ref_vec), float(lod) + 1.0)).rgb); indirect_specular_light = mix(indirect_sample_a, indirect_sample_b, blend); #else // USE_RADIANCE_CUBEMAP_ARRAY @@ -1559,7 +1563,7 @@ void main() { if (sc_scene_use_ambient_cubemap()) { vec3 ambient_dir = scene_data.radiance_inverse_xform * indirect_normal; #ifdef USE_RADIANCE_CUBEMAP_ARRAY - hvec3 cubemap_ambient = hvec3(texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ambient_dir, MAX_ROUGHNESS_LOD)).rgb); + hvec3 cubemap_ambient = hvec3(textureFix(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP, vec4(ambient_dir, MAX_ROUGHNESS_LOD)).rgb); #else hvec3 cubemap_ambient = hvec3(textureLod(samplerCube(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ambient_dir, MAX_ROUGHNESS_LOD).rgb); #endif //USE_RADIANCE_CUBEMAP_ARRAY @@ -1592,8 +1596,8 @@ void main() { float lod; half blend = half(modf(roughness_lod, lod)); - hvec3 clearcoat_sample_a = hvec3(texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod)).rgb); - hvec3 clearcoat_sample_b = hvec3(texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ref_vec, lod + 1)).rgb); + hvec3 clearcoat_sample_a = hvec3(textureFix(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP, vec4(ref_vec, lod)).rgb); + hvec3 clearcoat_sample_b = hvec3(textureFix(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP, vec4(ref_vec, lod + 1)).rgb); hvec3 clearcoat_light = mix(clearcoat_sample_a, clearcoat_sample_b, blend); #else diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl index 57aa34c67304..3ddd4fbfe44e 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl @@ -2,6 +2,7 @@ #define MAX_VIEWS 2 #include "../decal_data_inc.glsl" +#include "../metal_simulator_inc.glsl" #include "../scene_data_inc.glsl" #if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(BENT_NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) @@ -328,7 +329,7 @@ instances; #ifdef USE_RADIANCE_CUBEMAP_ARRAY -layout(set = 1, binding = 2) uniform textureCubeArray radiance_cubemap; +layout(set = 1, binding = 2) uniform textureCubeArrayFix radiance_cubemap; #else @@ -336,7 +337,7 @@ layout(set = 1, binding = 2) uniform textureCube radiance_cubemap; #endif -layout(set = 1, binding = 3) uniform textureCubeArray reflection_atlas; +layout(set = 1, binding = 3) uniform textureCubeArrayFix reflection_atlas; layout(set = 1, binding = 4) uniform texture2D shadow_atlas; diff --git a/servers/rendering/renderer_rd/shaders/metal_simulator_inc.glsl b/servers/rendering/renderer_rd/shaders/metal_simulator_inc.glsl new file mode 100644 index 000000000000..b55459aca4ee --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/metal_simulator_inc.glsl @@ -0,0 +1,150 @@ +#ifdef SIMULATE_CUBEMAP_ARRAYS +#define textureCubeArrayFix texture2DArray +#define samplerCubeArrayFix sampler2DArray +#else +#define textureCubeArrayFix textureCubeArray +#define samplerCubeArrayFix samplerCubeArray +#endif + +#ifdef SIMULATE_CUBEMAP_ARRAYS +vec3 simulateCoords(vec4 p_coords) { + vec3 dir = p_coords.xyz; + float index = p_coords.w; + vec3 absDir = abs(dir); + float axis; + vec2 uv; + int face; + if (absDir.x >= absDir.y && absDir.x >= absDir.z) { + axis = absDir.x; + uv = vec2(dir.z, dir.y) / axis; + face = dir.x > 0.0 ? 0 : 1; + if (dir.x < 0.0) { + uv.x = -uv.x; + } + } else if (absDir.y >= absDir.z) { + axis = absDir.y; + uv = vec2(dir.x, dir.z) / axis; + face = dir.y > 0.0 ? 2 : 3; + if (dir.y < 0.0) { + uv.y = -uv.y; + } + } else { + axis = absDir.z; + uv = vec2(dir.x, dir.y) / axis; + face = dir.z > 0.0 ? 4 : 5; + if (dir.z < 0.0) { + uv.x = -uv.x; + } + } + uv = 0.5 * (uv + 1.0); + float layer = index * 6.0 + float(face); + return vec3(uv, layer); +} +#else +vec4 simulateCoords(vec4 p_coords) { + return p_coords; +} +#endif + +ivec3 simulateSize(ivec3 p_size) { +#ifdef SIMULATE_CUBEMAP_ARRAYS + p_size.z /= 6; +#endif + return p_size; +} + +#ifdef SIMULATE_CUBEMAP_ARRAYS +struct Grad { + vec2 dx; + vec2 dy; +}; + +Grad simulateGrad(vec4 p_coords, vec3 p_dPdx, vec3 p_dPdy) { + vec3 dir = p_coords.xyz; + vec3 absDir = abs(dir); + vec2 a, adx, ady; + float b, bdx, bdy; + if (absDir.x >= absDir.y && absDir.x >= absDir.z) { + a = vec2(dir.z, dir.y); + adx = vec2(p_dPdx.z, p_dPdx.y); + ady = vec2(p_dPdy.z, p_dPdy.y); + b = dir.x; + bdx = p_dPdx.x; + if (dir.x < 0.0) { + a.x *= -1.0; + adx.x *= -1.0; + ady.x *= -1.0; + } + } else if (absDir.y >= absDir.z) { + a = vec2(dir.x, dir.z); + adx = vec2(p_dPdx.x, p_dPdx.z); + ady = vec2(p_dPdy.x, p_dPdy.z); + b = dir.y; + bdx = p_dPdx.y; + bdy = p_dPdy.y; + if (dir.y < 0.0) { + a.y *= -1.0; + adx.y *= -1.0; + ady.y *= -1.0; + } + } else { + a = vec2(dir.x, dir.y); + adx = vec2(p_dPdx.x, p_dPdx.y); + ady = vec2(p_dPdy.x, p_dPdy.y); + b = dir.z; + bdx = p_dPdx.z; + bdy = p_dPdy.z; + if (dir.z < 0.0) { + a.x *= -1.0; + adx.x *= -1.0; + ady.x *= -1.0; + } + } + vec2 dUVdx = (adx * b - a * bdx) / (b * b); + vec2 dUVdy = (ady * b - a * bdy) / (b * b); + return Grad(0.5 * dUVdx, 0.5 * dUVdy); +} +#else +struct Grad { + vec3 dx; + vec3 dy; +}; + +Grad simulateGrad(vec4 p_coords, vec3 p_dPdx, vec3 p_dPdy) { + return Grad(p_dPdx, p_dPdy); +} +#endif + +ivec3 textureSizeFix(samplerCubeArrayFix p_sampler, int p_lod) { + return simulateSize(textureSize(p_sampler, p_lod)); +} + +ivec3 textureSizeFix(textureCubeArrayFix p_texture, sampler p_sampler, int p_lod) { + return simulateSize(textureSize(samplerCubeArrayFix(p_texture, p_sampler), p_lod)); +} + +vec4 textureFix(samplerCubeArrayFix p_sampler, vec4 p_coords) { + return texture(p_sampler, simulateCoords(p_coords)); +} + +vec4 textureFix(textureCubeArrayFix p_texture, sampler p_sampler, vec4 p_coords) { + return texture(samplerCubeArrayFix(p_texture, p_sampler), simulateCoords(p_coords)); +} + +vec4 textureLodFix(samplerCubeArrayFix p_sampler, vec4 p_coords, float p_lod) { + return textureLod(p_sampler, simulateCoords(p_coords), p_lod); +} + +vec4 textureLodFix(textureCubeArrayFix p_texture, sampler p_sampler, vec4 p_coords, float p_lod) { + return textureLod(samplerCubeArrayFix(p_texture, p_sampler), simulateCoords(p_coords), p_lod); +} + +vec4 textureGradFix(samplerCubeArrayFix p_sampler, vec4 p_coords, vec3 p_dPdx, vec3 p_dPdy) { + Grad grad = simulateGrad(p_coords, p_dPdx, p_dPdy); + return textureGrad(p_sampler, simulateCoords(p_coords), grad.dx, grad.dy); +} + +vec4 textureGradFix(textureCubeArrayFix p_texture, sampler p_sampler, vec4 p_coords, vec3 p_dPdx, vec3 p_dPdy) { + Grad grad = simulateGrad(p_coords, p_dPdx, p_dPdy); + return textureGrad(samplerCubeArrayFix(p_texture, p_sampler), simulateCoords(p_coords), grad.dx, grad.dy); +} diff --git a/servers/rendering/renderer_rd/shaders/particles.glsl b/servers/rendering/renderer_rd/shaders/particles.glsl index 20aa6c208454..e87e0a8bc96c 100644 --- a/servers/rendering/renderer_rd/shaders/particles.glsl +++ b/servers/rendering/renderer_rd/shaders/particles.glsl @@ -4,6 +4,8 @@ #VERSION_DEFINES +#include "metal_simulator_inc.glsl" + layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; #define SDF_MAX_LENGTH 16384.0 diff --git a/servers/rendering/renderer_rd/shaders/particles_copy.glsl b/servers/rendering/renderer_rd/shaders/particles_copy.glsl index 93c4d1009d47..d18611bd9a25 100644 --- a/servers/rendering/renderer_rd/shaders/particles_copy.glsl +++ b/servers/rendering/renderer_rd/shaders/particles_copy.glsl @@ -4,6 +4,8 @@ #VERSION_DEFINES +#include "metal_simulator_inc.glsl" + layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; #define PARTICLE_FLAG_ACTIVE uint(1) diff --git a/servers/rendering/renderer_rd/shaders/scene_data_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_data_inc.glsl index 8f044d9d381d..f0cd8cb39357 100644 --- a/servers/rendering/renderer_rd/shaders/scene_data_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_data_inc.glsl @@ -3,6 +3,8 @@ // This enables us to use this UBO in our main scene render shaders but also in // effects that need access to this data. +#include "metal_simulator_inc.glsl" + #define SCENE_DATA_FLAGS_USE_AMBIENT_LIGHT (1 << 0) #define SCENE_DATA_FLAGS_USE_AMBIENT_CUBEMAP (1 << 1) #define SCENE_DATA_FLAGS_USE_REFLECTION_CUBEMAP (1 << 2) diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl index 9d8db2401bfc..d4452eca7d63 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl @@ -946,7 +946,7 @@ void reflection_process(uint ref_index, vec3 vertex, hvec3 ref_vec, hvec3 normal hvec4 reflection; half reflection_blend = max(half(0.0), blend - reflection_accum.a); - reflection.rgb = hvec3(textureLod(samplerCubeArray(reflection_atlas, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(local_ref_vec, reflections.data[ref_index].index), sqrt(roughness) * MAX_ROUGHNESS_LOD).rgb) * sc_luminance_multiplier(); + reflection.rgb = hvec3(textureLodFix(reflection_atlas, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP, vec4(local_ref_vec, reflections.data[ref_index].index), sqrt(roughness) * MAX_ROUGHNESS_LOD).rgb) * sc_luminance_multiplier(); reflection.rgb *= half(reflections.data[ref_index].exposure_normalization); reflection.a = reflection_blend; @@ -969,7 +969,7 @@ void reflection_process(uint ref_index, vec3 vertex, hvec3 ref_vec, hvec3 normal hvec4 ambient_out; half ambient_blend = max(half(0.0), blend - ambient_accum.a); - ambient_out.rgb = hvec3(textureLod(samplerCubeArray(reflection_atlas, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(local_amb_vec, reflections.data[ref_index].index), MAX_ROUGHNESS_LOD).rgb); + ambient_out.rgb = hvec3(textureLodFix(reflection_atlas, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP, vec4(local_amb_vec, reflections.data[ref_index].index), MAX_ROUGHNESS_LOD).rgb); ambient_out.rgb *= half(reflections.data[ref_index].exposure_normalization); ambient_out.a = ambient_blend; ambient_out.rgb *= ambient_out.a; diff --git a/servers/rendering/renderer_rd/shaders/skeleton.glsl b/servers/rendering/renderer_rd/shaders/skeleton.glsl index 894dee1728f0..fe7ca797966a 100644 --- a/servers/rendering/renderer_rd/shaders/skeleton.glsl +++ b/servers/rendering/renderer_rd/shaders/skeleton.glsl @@ -4,6 +4,8 @@ #VERSION_DEFINES +#include "metal_simulator_inc.glsl" + layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; layout(set = 0, binding = 1, std430) buffer restrict writeonly DstVertexData { 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 a822212a4fd9..83c13bf32f8c 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 @@ -140,7 +140,7 @@ void RenderSceneBuffersRD::cleanup() { } } -#ifdef METAL_ENABLED +#if defined(METAL_ENABLED) && !defined(IOS_SIMULATOR) if (mfx_spatial_context) { memdelete(mfx_spatial_context); mfx_spatial_context = nullptr; @@ -250,7 +250,7 @@ void RenderSceneBuffersRD::set_use_debanding(bool p_use_debanding) { use_debanding = p_use_debanding; } -#ifdef METAL_ENABLED +#if defined(METAL_ENABLED) && !defined(IOS_SIMULATOR) void RenderSceneBuffersRD::ensure_mfx(RendererRD::MFXSpatialEffect *p_effect) { if (mfx_spatial_context) { return; 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 11c593001d95..1218cbf5c0be 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 @@ -30,7 +30,7 @@ #pragma once -#ifdef METAL_ENABLED +#if defined(METAL_ENABLED) && !defined(IOS_SIMULATOR) #include "../effects/metal_fx.h" #endif #include "../effects/vrs.h" @@ -83,7 +83,7 @@ class RenderSceneBuffersRD : public RenderSceneBuffers { float texture_mipmap_bias = 0.0f; RS::ViewportAnisotropicFiltering anisotropic_filtering_level = RS::VIEWPORT_ANISOTROPY_4X; -#ifdef METAL_ENABLED +#if defined(METAL_ENABLED) && !defined(IOS_SIMULATOR) RendererRD::MFXSpatialContext *mfx_spatial_context = nullptr; #endif @@ -199,7 +199,7 @@ class RenderSceneBuffersRD : public RenderSceneBuffers { virtual void set_anisotropic_filtering_level(RS::ViewportAnisotropicFiltering p_anisotropic_filtering_level) override; virtual void set_use_debanding(bool p_use_debanding) override; -#ifdef METAL_ENABLED +#if defined(METAL_ENABLED) && !defined(IOS_SIMULATOR) void ensure_mfx(RendererRD::MFXSpatialEffect *p_effect); _FORCE_INLINE_ RendererRD::MFXSpatialContext *get_mfx_spatial_context() const { return mfx_spatial_context; } #endif diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index 657807560e1e..d6f3866b2b4b 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -3699,7 +3699,7 @@ bool TextureStorage::render_target_get_transparent(RID p_render_target) const { return rt->is_transparent; } -void TextureStorage::render_target_set_direct_to_screen(RID p_render_target, bool p_value) { +void TextureStorage::render_target_set_direct_to_screen(RID p_render_target, bool p_value, DisplayServer::WindowID p_direct_to_screen_id) { } bool TextureStorage::render_target_get_direct_to_screen(RID p_render_target) const { diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.h b/servers/rendering/renderer_rd/storage_rd/texture_storage.h index 4a4767f91159..7e99162ae755 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h @@ -753,7 +753,7 @@ class TextureStorage : public RendererTextureStorage { virtual Size2i render_target_get_size(RID p_render_target) const override; virtual void render_target_set_transparent(RID p_render_target, bool p_is_transparent) override; virtual bool render_target_get_transparent(RID p_render_target) const override; - virtual void render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) override; + virtual void render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen, DisplayServer::WindowID p_direct_to_screen_id) override; virtual bool render_target_get_direct_to_screen(RID p_render_target) const override; virtual bool render_target_was_used(RID p_render_target) const override; virtual void render_target_set_as_unused(RID p_render_target) override; diff --git a/servers/rendering/renderer_rd/uniform_set_cache_rd.cpp b/servers/rendering/renderer_rd/uniform_set_cache_rd.cpp index 54be667d2581..b9722d762740 100644 --- a/servers/rendering/renderer_rd/uniform_set_cache_rd.cpp +++ b/servers/rendering/renderer_rd/uniform_set_cache_rd.cpp @@ -79,4 +79,6 @@ UniformSetCacheRD::~UniformSetCacheRD() { if (cache_instances_used > 0) { ERR_PRINT("At exit: " + itos(cache_instances_used) + " uniform set cache instance(s) still in use."); } + ERR_FAIL_COND(singleton != this); + singleton = nullptr; } diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index 0c84348b6991..27a9e89f7eed 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -4332,4 +4332,7 @@ RendererSceneCull::~RendererSceneCull() { memdelete(light_culler); light_culler = nullptr; } + + ERR_FAIL_COND(singleton != this); + singleton = nullptr; } diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index 1ff3b2d9295d..fca7ee58d667 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -325,7 +325,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) { timestamp_vp_map[rt_id] = p_viewport->self; } - if (OS::get_singleton()->get_current_rendering_method() == "gl_compatibility") { + if (OS::get_singleton()->get_current_rendering_method() == "gl_compatibility" && p_viewport->viewport_to_screen != DisplayServer::INVALID_WINDOW_ID) { // This is currently needed for GLES to keep the current window being rendered to up to date DisplayServer::get_singleton()->gl_window_make_current(p_viewport->viewport_to_screen); } @@ -1101,8 +1101,8 @@ void RendererViewport::viewport_attach_to_screen(RID p_viewport, const Rect2 &p_ ERR_FAIL_NULL(viewport); if (p_screen != DisplayServer::INVALID_WINDOW_ID) { - // If using OpenGL we can optimize this operation by rendering directly to system_fbo - // instead of rendering to fbo and copying to system_fbo after + // If using OpenGL we can optimize this operation by rendering directly to the system fbo + // instead of rendering to fbo and copying to the system fbo after if (RSG::rasterizer->is_low_end() && viewport->viewport_render_direct_to_screen) { RSG::texture_storage->render_target_set_size(viewport->render_target, p_rect.size.x, p_rect.size.y, viewport->view_count); RSG::texture_storage->render_target_set_position(viewport->render_target, p_rect.position.x, p_rect.position.y); @@ -1136,7 +1136,7 @@ void RendererViewport::viewport_set_render_direct_to_screen(RID p_viewport, bool RSG::texture_storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y, viewport->view_count); } - RSG::texture_storage->render_target_set_direct_to_screen(viewport->render_target, p_enable); + RSG::texture_storage->render_target_set_direct_to_screen(viewport->render_target, p_enable, viewport->viewport_to_screen); viewport->viewport_render_direct_to_screen = p_enable; // if attached to screen already, setup screen size and position, this needs to happen after setting flag to avoid an unnecessary buffer allocation diff --git a/servers/rendering/rendering_context_driver.cpp b/servers/rendering/rendering_context_driver.cpp index b623be40980f..c171624bffd4 100644 --- a/servers/rendering/rendering_context_driver.cpp +++ b/servers/rendering/rendering_context_driver.cpp @@ -42,10 +42,21 @@ RenderingContextDriver::SurfaceID RenderingContextDriver::surface_get_from_windo } } -Error RenderingContextDriver::window_create(DisplayServer::WindowID p_window, const void *p_platform_data) { - SurfaceID surface = surface_create(p_platform_data); +DisplayServer::WindowID RenderingContextDriver::window_get_from_surface(SurfaceID p_surface) const { + HashMap::ConstIterator it = surface_window_map.find(p_surface); + if (it != surface_window_map.end()) { + return it->value; + } else { + return DisplayServer::INVALID_WINDOW_ID; + } +} + +Error RenderingContextDriver::window_create(DisplayServer::WindowID p_window, Ref p_native_surface) { + SurfaceID surface = surface_create(p_native_surface); if (surface != 0) { window_surface_map[p_window] = surface; + surface_window_map[surface] = p_window; + return OK; } else { return ERR_CANT_CREATE; @@ -59,6 +70,14 @@ void RenderingContextDriver::window_set_size(DisplayServer::WindowID p_window, u } } +void RenderingContextDriver::window_get_size(DisplayServer::WindowID p_window, uint32_t &r_width, uint32_t &r_height) { + SurfaceID surface = surface_get_from_window(p_window); + if (surface) { + r_width = surface_get_width(surface); + r_height = surface_get_height(surface); + } +} + void RenderingContextDriver::window_set_vsync_mode(DisplayServer::WindowID p_window, DisplayServer::VSyncMode p_vsync_mode) { SurfaceID surface = surface_get_from_window(p_window); if (surface) { @@ -82,6 +101,7 @@ void RenderingContextDriver::window_destroy(DisplayServer::WindowID p_window) { } window_surface_map.erase(p_window); + surface_window_map.erase(surface); } String RenderingContextDriver::get_driver_and_device_memory_report() const { diff --git a/servers/rendering/rendering_context_driver.h b/servers/rendering/rendering_context_driver.h index 95cbabc8a793..8e954571d8ec 100644 --- a/servers/rendering/rendering_context_driver.h +++ b/servers/rendering/rendering_context_driver.h @@ -30,6 +30,8 @@ #pragma once +#include "core/object/object.h" +#include "rendering_native_surface.h" #include "servers/display_server.h" class RenderingDeviceDriver; @@ -40,11 +42,14 @@ class RenderingContextDriver { private: HashMap window_surface_map; + HashMap surface_window_map; public: SurfaceID surface_get_from_window(DisplayServer::WindowID p_window) const; - Error window_create(DisplayServer::WindowID p_window, const void *p_platform_data); + DisplayServer::WindowID window_get_from_surface(SurfaceID p_surface) const; + Error window_create(DisplayServer::WindowID p_window, Ref p_native_surface); void window_set_size(DisplayServer::WindowID p_window, uint32_t p_width, uint32_t p_height); + void window_get_size(DisplayServer::WindowID p_window, uint32_t &r_width, uint32_t &r_height); void window_set_vsync_mode(DisplayServer::WindowID p_window, DisplayServer::VSyncMode p_vsync_mode); DisplayServer::VSyncMode window_get_vsync_mode(DisplayServer::WindowID p_window) const; void window_destroy(DisplayServer::WindowID p_window); @@ -93,7 +98,7 @@ class RenderingContextDriver { virtual bool device_supports_present(uint32_t p_device_index, SurfaceID p_surface) const = 0; virtual RenderingDeviceDriver *driver_create() = 0; virtual void driver_free(RenderingDeviceDriver *p_driver) = 0; - virtual SurfaceID surface_create(const void *p_platform_data) = 0; + virtual SurfaceID surface_create(Ref p_native_surface) = 0; virtual void surface_set_size(SurfaceID p_surface, uint32_t p_width, uint32_t p_height) = 0; virtual void surface_set_vsync_mode(SurfaceID p_surface, DisplayServer::VSyncMode p_vsync_mode) = 0; virtual DisplayServer::VSyncMode surface_get_vsync_mode(SurfaceID p_surface) const = 0; diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index eb7d27e4a639..c60694e57b39 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -285,7 +285,7 @@ Error RenderingDevice::_staging_buffer_allocate(StagingBuffers &p_staging_buffer r_alloc_offset = 0; // See if we can use current block. - if (p_staging_buffers.blocks[p_staging_buffers.current].frame_used == frames_drawn) { + if (p_staging_buffers.blocks[p_staging_buffers.current].frame_used == frames->get_frames_drawn()) { // We used this block this frame, let's see if there is still room. uint32_t write_from = p_staging_buffers.blocks[p_staging_buffers.current].fill_amount; @@ -316,7 +316,7 @@ Error RenderingDevice::_staging_buffer_allocate(StagingBuffers &p_staging_buffer // Before doing anything, though, let's check that we didn't manage to fill all blocks. // Possible in a single frame. - if (p_staging_buffers.blocks[p_staging_buffers.current].frame_used == frames_drawn) { + if (p_staging_buffers.blocks[p_staging_buffers.current].frame_used == frames->get_frames_drawn()) { // Guess we did.. ok, let's see if we can insert a new block. if ((uint64_t)p_staging_buffers.blocks.size() * p_staging_buffers.block_size < p_staging_buffers.max_size) { // We can, so we are safe. @@ -325,7 +325,7 @@ Error RenderingDevice::_staging_buffer_allocate(StagingBuffers &p_staging_buffer return err; } // Claim for this frame. - p_staging_buffers.blocks.write[p_staging_buffers.current].frame_used = frames_drawn; + p_staging_buffers.blocks.write[p_staging_buffers.current].frame_used = frames->get_frames_drawn(); } else { // Ok, worst case scenario, all the staging buffers belong to this frame // and this frame is not even done. @@ -340,9 +340,9 @@ Error RenderingDevice::_staging_buffer_allocate(StagingBuffers &p_staging_buffer } } - } else if (p_staging_buffers.blocks[p_staging_buffers.current].frame_used <= frames_drawn - frames.size()) { + } else if (p_staging_buffers.blocks[p_staging_buffers.current].frame_used <= frames->get_frames_drawn() - frames->get_number_of_frames()) { // This is an old block, which was already processed, let's reuse. - p_staging_buffers.blocks.write[p_staging_buffers.current].frame_used = frames_drawn; + p_staging_buffers.blocks.write[p_staging_buffers.current].frame_used = frames->get_frames_drawn(); p_staging_buffers.blocks.write[p_staging_buffers.current].fill_amount = 0; } else { // This block may still be in use, let's not touch it unless we have to, so.. can we create a new one? @@ -353,7 +353,7 @@ Error RenderingDevice::_staging_buffer_allocate(StagingBuffers &p_staging_buffer return err; } // Claim for this frame. - p_staging_buffers.blocks.write[p_staging_buffers.current].frame_used = frames_drawn; + p_staging_buffers.blocks.write[p_staging_buffers.current].frame_used = frames->get_frames_drawn(); } else { // Oops, we are out of room and we can't create more. // Let's flush older frames. @@ -387,7 +387,7 @@ void RenderingDevice::_staging_buffer_execute_required_action(StagingBuffers &p_ } // Claim for current frame. - p_staging_buffers.blocks.write[p_staging_buffers.current].frame_used = frames_drawn; + p_staging_buffers.blocks.write[p_staging_buffers.current].frame_used = frames->get_frames_drawn(); } break; case STAGING_REQUIRED_ACTION_STALL_PREVIOUS: { _stall_for_previous_frames(); @@ -395,7 +395,7 @@ void RenderingDevice::_staging_buffer_execute_required_action(StagingBuffers &p_ for (int i = 0; i < p_staging_buffers.blocks.size(); i++) { // Clear all blocks but the ones from this frame. int block_idx = (i + p_staging_buffers.current) % p_staging_buffers.blocks.size(); - if (p_staging_buffers.blocks[block_idx].frame_used == frames_drawn) { + if (p_staging_buffers.blocks[block_idx].frame_used == frames->get_frames_drawn()) { break; // Ok, we reached something from this frame, abort. } @@ -404,7 +404,7 @@ void RenderingDevice::_staging_buffer_execute_required_action(StagingBuffers &p_ } // Claim for current frame. - p_staging_buffers.blocks.write[p_staging_buffers.current].frame_used = frames_drawn; + p_staging_buffers.blocks.write[p_staging_buffers.current].frame_used = frames->get_frames_drawn(); } break; default: { DEV_ASSERT(false && "Unknown required action."); @@ -705,7 +705,7 @@ Error RenderingDevice::buffer_get_data_async(RID p_buffer, const Callable &p_cal BufferGetDataRequest get_data_request; get_data_request.callback = p_callback; - get_data_request.frame_local_index = frames[frame].download_buffer_copy_regions.size(); + get_data_request.frame_local_index = frames->get_current_frame().download_buffer_copy_regions.size(); get_data_request.size = p_size; const uint32_t required_align = 32; @@ -729,7 +729,7 @@ Error RenderingDevice::buffer_get_data_async(RID p_buffer, const Callable &p_cal for (uint32_t i = 0; i < get_data_request.frame_local_count; i++) { uint32_t local_index = get_data_request.frame_local_index + i; - draw_graph.add_buffer_get_data(buffer->driver_id, buffer->draw_tracker, frames[frame].download_buffer_staging_buffers[local_index], frames[frame].download_buffer_copy_regions[local_index]); + draw_graph.add_buffer_get_data(buffer->driver_id, buffer->draw_tracker, frames->get_current_frame().download_buffer_staging_buffers[local_index], frames->get_current_frame().download_buffer_copy_regions[local_index]); } } @@ -737,7 +737,7 @@ Error RenderingDevice::buffer_get_data_async(RID p_buffer, const Callable &p_cal if (flush_frames) { get_data_request.frame_local_count = 0; - get_data_request.frame_local_index = frames[frame].download_buffer_copy_regions.size(); + get_data_request.frame_local_index = frames->get_current_frame().download_buffer_copy_regions.size(); } RDD::BufferCopyRegion region; @@ -745,8 +745,8 @@ Error RenderingDevice::buffer_get_data_async(RID p_buffer, const Callable &p_cal region.dst_offset = block_write_offset; region.size = block_write_amount; - frames[frame].download_buffer_staging_buffers.push_back(download_staging_buffers.blocks[download_staging_buffers.current].driver_id); - frames[frame].download_buffer_copy_regions.push_back(region); + frames->get_current_frame().download_buffer_staging_buffers.push_back(download_staging_buffers.blocks[download_staging_buffers.current].driver_id); + frames->get_current_frame().download_buffer_copy_regions.push_back(region); get_data_request.frame_local_count++; download_staging_buffers.blocks.write[download_staging_buffers.current].fill_amount = block_write_offset + block_write_amount; @@ -763,10 +763,10 @@ Error RenderingDevice::buffer_get_data_async(RID p_buffer, const Callable &p_cal for (uint32_t i = 0; i < get_data_request.frame_local_count; i++) { uint32_t local_index = get_data_request.frame_local_index + i; - draw_graph.add_buffer_get_data(buffer->driver_id, buffer->draw_tracker, frames[frame].download_buffer_staging_buffers[local_index], frames[frame].download_buffer_copy_regions[local_index]); + draw_graph.add_buffer_get_data(buffer->driver_id, buffer->draw_tracker, frames->get_current_frame().download_buffer_staging_buffers[local_index], frames->get_current_frame().download_buffer_copy_regions[local_index]); } - frames[frame].download_buffer_get_data_requests.push_back(get_data_request); + frames->get_current_frame().download_buffer_get_data_requests.push_back(get_data_request); } return OK; @@ -2116,7 +2116,7 @@ Error RenderingDevice::texture_get_data_async(RID p_texture, uint32_t p_layer, c TextureGetDataRequest get_data_request; get_data_request.callback = p_callback; - get_data_request.frame_local_index = frames[frame].download_buffer_texture_copy_regions.size(); + get_data_request.frame_local_index = frames->get_current_frame().download_buffer_texture_copy_regions.size(); get_data_request.width = tex->width; get_data_request.height = tex->height; get_data_request.depth = tex->depth; @@ -2163,7 +2163,7 @@ Error RenderingDevice::texture_get_data_async(RID p_texture, uint32_t p_layer, c if (flush_frames) { for (uint32_t j = 0; j < get_data_request.frame_local_count; j++) { uint32_t local_index = get_data_request.frame_local_index + j; - draw_graph.add_texture_get_data(tex->driver_id, tex->draw_tracker, frames[frame].download_texture_staging_buffers[local_index], frames[frame].download_buffer_texture_copy_regions[local_index]); + draw_graph.add_texture_get_data(tex->driver_id, tex->draw_tracker, frames->get_current_frame().download_texture_staging_buffers[local_index], frames->get_current_frame().download_buffer_texture_copy_regions[local_index]); } } @@ -2171,7 +2171,7 @@ Error RenderingDevice::texture_get_data_async(RID p_texture, uint32_t p_layer, c if (flush_frames) { get_data_request.frame_local_count = 0; - get_data_request.frame_local_index = frames[frame].download_buffer_texture_copy_regions.size(); + get_data_request.frame_local_index = frames->get_current_frame().download_buffer_texture_copy_regions.size(); } RDD::BufferTextureCopyRegion copy_region; @@ -2182,9 +2182,9 @@ Error RenderingDevice::texture_get_data_async(RID p_texture, uint32_t p_layer, c copy_region.texture_subresources.layer_count = 1; copy_region.texture_offset = Vector3i(x, y, z); copy_region.texture_region_size = Vector3i(region_logic_w, region_logic_h, 1); - frames[frame].download_texture_staging_buffers.push_back(download_staging_buffers.blocks[download_staging_buffers.current].driver_id); - frames[frame].download_buffer_texture_copy_regions.push_back(copy_region); - frames[frame].download_texture_mipmap_offsets.push_back(mipmap_offset + (tight_mip_size / d) * z); + frames->get_current_frame().download_texture_staging_buffers.push_back(download_staging_buffers.blocks[download_staging_buffers.current].driver_id); + frames->get_current_frame().download_buffer_texture_copy_regions.push_back(copy_region); + frames->get_current_frame().download_texture_mipmap_offsets.push_back(mipmap_offset + (tight_mip_size / d) * z); get_data_request.frame_local_count++; download_staging_buffers.blocks.write[download_staging_buffers.current].fill_amount = block_write_offset + block_write_amount; @@ -2200,10 +2200,10 @@ Error RenderingDevice::texture_get_data_async(RID p_texture, uint32_t p_layer, c if (get_data_request.frame_local_count > 0) { for (uint32_t i = 0; i < get_data_request.frame_local_count; i++) { uint32_t local_index = get_data_request.frame_local_index + i; - draw_graph.add_texture_get_data(tex->driver_id, tex->draw_tracker, frames[frame].download_texture_staging_buffers[local_index], frames[frame].download_buffer_texture_copy_regions[local_index]); + draw_graph.add_texture_get_data(tex->driver_id, tex->draw_tracker, frames->get_current_frame().download_texture_staging_buffers[local_index], frames->get_current_frame().download_buffer_texture_copy_regions[local_index]); } - frames[frame].download_texture_get_data_requests.push_back(get_data_request); + frames->get_current_frame().download_texture_get_data_requests.push_back(get_data_request); } return OK; @@ -3923,7 +3923,7 @@ RID RenderingDevice::uniform_set_create(const VectorView &p_uniform } } - RDD::UniformSetID driver_uniform_set = driver->uniform_set_create(driver_uniforms, shader->driver_id, p_shader_set, p_linear_pool ? frame : -1); + RDD::UniformSetID driver_uniform_set = driver->uniform_set_create(driver_uniforms, shader->driver_id, p_shader_set, p_linear_pool ? frames->get_frame_index() : -1); ERR_FAIL_COND_V(!driver_uniform_set, RID()); UniformSet uniform_set; @@ -4264,10 +4264,10 @@ Error RenderingDevice::screen_prepare_for_drawing(DisplayServer::WindowID p_scre // If this frame has already queued this swap chain for presentation, we present it and remove it from the pending list. uint32_t to_present_index = 0; - while (to_present_index < frames[frame].swap_chains_to_present.size()) { - if (frames[frame].swap_chains_to_present[to_present_index] == it->value) { + while (to_present_index < frames->get_current_frame().swap_chains_to_present.size()) { + if (frames->get_current_frame().swap_chains_to_present[to_present_index] == it->value) { driver->command_queue_execute_and_present(present_queue, {}, {}, {}, {}, it->value); - frames[frame].swap_chains_to_present.remove_at(to_present_index); + frames->get_current_frame().swap_chains_to_present.remove_at(to_present_index); } else { to_present_index++; } @@ -4297,7 +4297,7 @@ Error RenderingDevice::screen_prepare_for_drawing(DisplayServer::WindowID p_scre // Store the framebuffer that will be used next to draw to this screen. screen_framebuffers[p_screen] = framebuffer; - frames[frame].swap_chains_to_present.push_back(it->value); + frames->get_current_frame().swap_chains_to_present.push_back(it->value); return OK; } @@ -4345,6 +4345,10 @@ RenderingDevice::FramebufferFormatID RenderingDevice::screen_get_framebuffer_for return const_cast(this)->framebuffer_format_create(screen_attachment); } +RDD::SwapChainID RenderingDevice::screen_get_swapchain(DisplayServer::WindowID p_screen) { + return screen_swap_chains[p_screen]; +} + Error RenderingDevice::screen_free(DisplayServer::WindowID p_screen) { _THREAD_SAFE_METHOD_ @@ -5740,7 +5744,7 @@ void RenderingDevice::_submit_transfer_worker(TransferWorker *p_transfer_worker, for (uint32_t i = 0; i < p_signal_semaphores.size(); i++) { // Indicate the frame should wait on these semaphores before executing the main command buffer. - frames[frame].semaphores_to_wait_on.push_back(p_signal_semaphores[i]); + frames->get_current_frame().semaphores_to_wait_on.push_back(p_signal_semaphores[i]); } p_transfer_worker->submitted = true; @@ -5831,7 +5835,7 @@ void RenderingDevice::_submit_transfer_workers(RDD::CommandBufferID p_draw_comma { MutexLock lock(worker->thread_mutex); if (worker->recording) { - VectorView semaphores = p_draw_command_buffer ? frames[frame].transfer_worker_semaphores[i] : VectorView(); + VectorView semaphores = p_draw_command_buffer ? frames->get_current_frame().transfer_worker_semaphores[i] : VectorView(); _end_transfer_worker(worker); _submit_transfer_worker(worker, semaphores); } @@ -6085,11 +6089,11 @@ void RenderingDevice::_free_internal(RID p_id) { } } - frames[frame].textures_to_dispose_of.push_back(*texture); + frames->get_current_frame().textures_to_dispose_of.push_back(*texture); texture_owner.free(p_id); } else if (framebuffer_owner.owns(p_id)) { Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_id); - frames[frame].framebuffers_to_dispose_of.push_back(*framebuffer); + frames->get_current_frame().framebuffers_to_dispose_of.push_back(*framebuffer); if (framebuffer->invalidated_callback != nullptr) { framebuffer->invalidated_callback(framebuffer->invalidated_callback_userdata); @@ -6098,14 +6102,14 @@ void RenderingDevice::_free_internal(RID p_id) { framebuffer_owner.free(p_id); } else if (sampler_owner.owns(p_id)) { RDD::SamplerID sampler_driver_id = *sampler_owner.get_or_null(p_id); - frames[frame].samplers_to_dispose_of.push_back(sampler_driver_id); + frames->get_current_frame().samplers_to_dispose_of.push_back(sampler_driver_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); _check_transfer_worker_buffer(vertex_buffer); RDG::resource_tracker_free(vertex_buffer->draw_tracker); - frames[frame].buffers_to_dispose_of.push_back(*vertex_buffer); + frames->get_current_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); @@ -6114,14 +6118,14 @@ void RenderingDevice::_free_internal(RID p_id) { _check_transfer_worker_buffer(index_buffer); RDG::resource_tracker_free(index_buffer->draw_tracker); - frames[frame].buffers_to_dispose_of.push_back(*index_buffer); + frames->get_current_frame().buffers_to_dispose_of.push_back(*index_buffer); index_buffer_owner.free(p_id); } else if (index_array_owner.owns(p_id)) { index_array_owner.free(p_id); } else if (shader_owner.owns(p_id)) { Shader *shader = shader_owner.get_or_null(p_id); if (shader->driver_id) { // Not placeholder? - frames[frame].shaders_to_dispose_of.push_back(*shader); + frames->get_current_frame().shaders_to_dispose_of.push_back(*shader); } shader_owner.free(p_id); } else if (uniform_buffer_owner.owns(p_id)) { @@ -6129,25 +6133,25 @@ void RenderingDevice::_free_internal(RID p_id) { _check_transfer_worker_buffer(uniform_buffer); RDG::resource_tracker_free(uniform_buffer->draw_tracker); - frames[frame].buffers_to_dispose_of.push_back(*uniform_buffer); + frames->get_current_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); _check_transfer_worker_buffer(texture_buffer); RDG::resource_tracker_free(texture_buffer->draw_tracker); - frames[frame].buffers_to_dispose_of.push_back(*texture_buffer); + frames->get_current_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); _check_transfer_worker_buffer(storage_buffer); RDG::resource_tracker_free(storage_buffer->draw_tracker); - frames[frame].buffers_to_dispose_of.push_back(*storage_buffer); + frames->get_current_frame().buffers_to_dispose_of.push_back(*storage_buffer); storage_buffer_owner.free(p_id); } else if (uniform_set_owner.owns(p_id)) { UniformSet *uniform_set = uniform_set_owner.get_or_null(p_id); - frames[frame].uniform_sets_to_dispose_of.push_back(*uniform_set); + frames->get_current_frame().uniform_sets_to_dispose_of.push_back(*uniform_set); uniform_set_owner.free(p_id); if (uniform_set->invalidated_callback != nullptr) { @@ -6155,11 +6159,11 @@ void RenderingDevice::_free_internal(RID p_id) { } } else if (render_pipeline_owner.owns(p_id)) { RenderPipeline *pipeline = render_pipeline_owner.get_or_null(p_id); - frames[frame].render_pipelines_to_dispose_of.push_back(*pipeline); + frames->get_current_frame().render_pipelines_to_dispose_of.push_back(*pipeline); render_pipeline_owner.free(p_id); } else if (compute_pipeline_owner.owns(p_id)) { ComputePipeline *pipeline = compute_pipeline_owner.get_or_null(p_id); - frames[frame].compute_pipelines_to_dispose_of.push_back(*pipeline); + frames->get_current_frame().compute_pipelines_to_dispose_of.push_back(*pipeline); compute_pipeline_owner.free(p_id); } else { #ifdef DEV_ENABLED @@ -6169,7 +6173,7 @@ void RenderingDevice::_free_internal(RID p_id) { #endif } - frames_pending_resources_for_processing = uint32_t(frames.size()); + frames_pending_resources_for_processing = uint32_t(frames->get_number_of_frames()); } // The full list of resources that can be named is in the VkObjectType enum. @@ -6283,7 +6287,7 @@ void RenderingDevice::swap_buffers(bool p_present) { _execute_frame(p_present); // Advance to the next frame and begin recording again. - frame = (frame + 1) % frames.size(); + frames->set_frame_index((frames->get_frame_index() + 1) % frames->get_number_of_frames()); _begin_frame(true); } @@ -6310,59 +6314,59 @@ void RenderingDevice::sync() { void RenderingDevice::_free_pending_resources(int p_frame) { // Free in dependency usage order, so nothing weird happens. // Pipelines. - while (frames[p_frame].render_pipelines_to_dispose_of.front()) { - RenderPipeline *pipeline = &frames[p_frame].render_pipelines_to_dispose_of.front()->get(); + while (frames->get_frame(p_frame).render_pipelines_to_dispose_of.front()) { + RenderPipeline *pipeline = &frames->get_frame(p_frame).render_pipelines_to_dispose_of.front()->get(); driver->pipeline_free(pipeline->driver_id); - frames[p_frame].render_pipelines_to_dispose_of.pop_front(); + frames->get_frame(p_frame).render_pipelines_to_dispose_of.pop_front(); } - while (frames[p_frame].compute_pipelines_to_dispose_of.front()) { - ComputePipeline *pipeline = &frames[p_frame].compute_pipelines_to_dispose_of.front()->get(); + while (frames->get_frame(p_frame).compute_pipelines_to_dispose_of.front()) { + ComputePipeline *pipeline = &frames->get_frame(p_frame).compute_pipelines_to_dispose_of.front()->get(); driver->pipeline_free(pipeline->driver_id); - frames[p_frame].compute_pipelines_to_dispose_of.pop_front(); + frames->get_frame(p_frame).compute_pipelines_to_dispose_of.pop_front(); } // Uniform sets. - while (frames[p_frame].uniform_sets_to_dispose_of.front()) { - UniformSet *uniform_set = &frames[p_frame].uniform_sets_to_dispose_of.front()->get(); + while (frames->get_frame(p_frame).uniform_sets_to_dispose_of.front()) { + UniformSet *uniform_set = &frames->get_frame(p_frame).uniform_sets_to_dispose_of.front()->get(); driver->uniform_set_free(uniform_set->driver_id); - frames[p_frame].uniform_sets_to_dispose_of.pop_front(); + frames->get_frame(p_frame).uniform_sets_to_dispose_of.pop_front(); } // Shaders. - while (frames[p_frame].shaders_to_dispose_of.front()) { - Shader *shader = &frames[p_frame].shaders_to_dispose_of.front()->get(); + while (frames->get_frame(p_frame).shaders_to_dispose_of.front()) { + Shader *shader = &frames->get_frame(p_frame).shaders_to_dispose_of.front()->get(); driver->shader_free(shader->driver_id); - frames[p_frame].shaders_to_dispose_of.pop_front(); + frames->get_frame(p_frame).shaders_to_dispose_of.pop_front(); } // Samplers. - while (frames[p_frame].samplers_to_dispose_of.front()) { - RDD::SamplerID sampler = frames[p_frame].samplers_to_dispose_of.front()->get(); + while (frames->get_frame(p_frame).samplers_to_dispose_of.front()) { + RDD::SamplerID sampler = frames->get_frame(p_frame).samplers_to_dispose_of.front()->get(); driver->sampler_free(sampler); - frames[p_frame].samplers_to_dispose_of.pop_front(); + frames->get_frame(p_frame).samplers_to_dispose_of.pop_front(); } // Framebuffers. - while (frames[p_frame].framebuffers_to_dispose_of.front()) { - Framebuffer *framebuffer = &frames[p_frame].framebuffers_to_dispose_of.front()->get(); + while (frames->get_frame(p_frame).framebuffers_to_dispose_of.front()) { + Framebuffer *framebuffer = &frames->get_frame(p_frame).framebuffers_to_dispose_of.front()->get(); draw_graph.framebuffer_cache_free(driver, framebuffer->framebuffer_cache); - frames[p_frame].framebuffers_to_dispose_of.pop_front(); + frames->get_frame(p_frame).framebuffers_to_dispose_of.pop_front(); } // Textures. - while (frames[p_frame].textures_to_dispose_of.front()) { - Texture *texture = &frames[p_frame].textures_to_dispose_of.front()->get(); + while (frames->get_frame(p_frame).textures_to_dispose_of.front()) { + Texture *texture = &frames->get_frame(p_frame).textures_to_dispose_of.front()->get(); if (texture->bound) { WARN_PRINT("Deleted a texture while it was bound."); } @@ -6372,16 +6376,16 @@ void RenderingDevice::_free_pending_resources(int p_frame) { texture_memory -= driver->texture_get_allocation_size(texture->driver_id); driver->texture_free(texture->driver_id); - frames[p_frame].textures_to_dispose_of.pop_front(); + frames->get_frame(p_frame).textures_to_dispose_of.pop_front(); } // Buffers. - while (frames[p_frame].buffers_to_dispose_of.front()) { - Buffer &buffer = frames[p_frame].buffers_to_dispose_of.front()->get(); + while (frames->get_frame(p_frame).buffers_to_dispose_of.front()) { + Buffer &buffer = frames->get_frame(p_frame).buffers_to_dispose_of.front()->get(); driver->buffer_free(buffer.driver_id); buffer_memory -= buffer.size; - frames[p_frame].buffers_to_dispose_of.pop_front(); + frames->get_frame(p_frame).buffers_to_dispose_of.pop_front(); } if (frames_pending_resources_for_processing > 0u) { @@ -6390,7 +6394,7 @@ void RenderingDevice::_free_pending_resources(int p_frame) { } uint32_t RenderingDevice::get_frame_delay() const { - return frames.size(); + return frames->get_number_of_frames(); } uint64_t RenderingDevice::get_memory_usage(MemoryType p_type) const { @@ -6413,27 +6417,28 @@ uint64_t RenderingDevice::get_memory_usage(MemoryType p_type) const { void RenderingDevice::_begin_frame(bool p_presented) { // Before writing to this frame, wait for it to be finished. - _stall_for_frame(frame); + _stall_for_frame(frames->get_frame_index()); if (command_pool_reset_enabled) { - bool reset = driver->command_pool_reset(frames[frame].command_pool); + bool reset = driver->command_pool_reset(frames->get_current_frame().command_pool); ERR_FAIL_COND(!reset); } if (p_presented) { update_perf_report(); - driver->linear_uniform_set_pools_reset(frame); + driver->linear_uniform_set_pools_reset(frames->get_frame_index()); } // Begin recording on the frame's command buffers. - driver->begin_segment(frame, frames_drawn++); - driver->command_buffer_begin(frames[frame].command_buffer); + driver->begin_segment(frames->get_frame_index(), frames->get_frames_drawn()); + frames->increment_frames_drawn(); + driver->command_buffer_begin(frames->get_current_frame().command_buffer); // Reset the graph. draw_graph.begin(); // Erase pending resources. - _free_pending_resources(frame); + _free_pending_resources(frames->get_frame_index()); // Advance staging buffers if used. if (upload_staging_buffers.used) { @@ -6446,16 +6451,16 @@ void RenderingDevice::_begin_frame(bool p_presented) { download_staging_buffers.used = false; } - if (frames[frame].timestamp_count) { - driver->timestamp_query_pool_get_results(frames[frame].timestamp_pool, frames[frame].timestamp_count, frames[frame].timestamp_result_values.ptr()); - driver->command_timestamp_query_pool_reset(frames[frame].command_buffer, frames[frame].timestamp_pool, frames[frame].timestamp_count); - SWAP(frames[frame].timestamp_names, frames[frame].timestamp_result_names); - SWAP(frames[frame].timestamp_cpu_values, frames[frame].timestamp_cpu_result_values); + if (frames->get_current_frame().timestamp_count) { + driver->timestamp_query_pool_get_results(frames->get_current_frame().timestamp_pool, frames->get_current_frame().timestamp_count, frames->get_current_frame().timestamp_result_values.ptr()); + driver->command_timestamp_query_pool_reset(frames->get_current_frame().command_buffer, frames->get_current_frame().timestamp_pool, frames->get_current_frame().timestamp_count); + SWAP(frames->get_current_frame().timestamp_names, frames->get_current_frame().timestamp_result_names); + SWAP(frames->get_current_frame().timestamp_cpu_values, frames->get_current_frame().timestamp_cpu_result_values); } - frames[frame].timestamp_result_count = frames[frame].timestamp_count; - frames[frame].timestamp_count = 0; - frames[frame].index = Engine::get_singleton()->get_frames_drawn(); + frames->get_current_frame().timestamp_result_count = frames->get_current_frame().timestamp_count; + frames->get_current_frame().timestamp_count = 0; + frames->get_current_frame().index = Engine::get_singleton()->get_frames_drawn(); } void RenderingDevice::_end_frame() { @@ -6468,11 +6473,11 @@ void RenderingDevice::_end_frame() { } // The command buffer must be copied into a stack variable as the driver workarounds can change the command buffer in use. - RDD::CommandBufferID command_buffer = frames[frame].command_buffer; + RDD::CommandBufferID command_buffer = frames->get_current_frame().command_buffer; _submit_transfer_workers(command_buffer); _submit_transfer_barriers(command_buffer); - draw_graph.end(RENDER_GRAPH_REORDER, RENDER_GRAPH_FULL_BARRIERS, command_buffer, frames[frame].command_buffer_pool); + draw_graph.end(RENDER_GRAPH_REORDER, RENDER_GRAPH_FULL_BARRIERS, command_buffer, frames->get_current_frame().command_buffer_pool); driver->command_buffer_end(command_buffer); driver->end_segment(); } @@ -6483,7 +6488,7 @@ void RenderingDevice::execute_chained_cmds(bool p_present_swap_chain, RenderingD // Normally there's only one command buffer, but driver workarounds can force situations where // there'll be more. uint32_t command_buffer_count = 1; - RDG::CommandBufferPool &buffer_pool = frames[frame].command_buffer_pool; + RDG::CommandBufferPool &buffer_pool = frames->get_current_frame().command_buffer_pool; if (buffer_pool.buffers_used > 0) { command_buffer_count += buffer_pool.buffers_used; buffer_pool.buffers_used = 0; @@ -6496,7 +6501,7 @@ void RenderingDevice::execute_chained_cmds(bool p_present_swap_chain, RenderingD // Adreno workaround on mobile, only if the workaround is active). Thus we must execute all of them // and chain them together via semaphores as dependent executions. thread_local LocalVector wait_semaphores; - wait_semaphores = frames[frame].semaphores_to_wait_on; + wait_semaphores = frames->get_current_frame().semaphores_to_wait_on; for (uint32_t i = 0; i < command_buffer_count; i++) { RDD::CommandBufferID command_buffer; @@ -6505,7 +6510,7 @@ void RenderingDevice::execute_chained_cmds(bool p_present_swap_chain, RenderingD if (i > 0) { command_buffer = buffer_pool.buffers[i - 1]; } else { - command_buffer = frames[frame].command_buffer; + command_buffer = frames->get_current_frame().command_buffer; } if (i == (command_buffer_count - 1)) { @@ -6515,7 +6520,7 @@ void RenderingDevice::execute_chained_cmds(bool p_present_swap_chain, RenderingD if (p_present_swap_chain) { // Just present the swap chains as part of the last command execution. - swap_chains = frames[frame].swap_chains_to_present; + swap_chains = frames->get_current_frame().swap_chains_to_present; } } else { signal_semaphore = buffer_pool.semaphores[i]; @@ -6531,72 +6536,73 @@ void RenderingDevice::execute_chained_cmds(bool p_present_swap_chain, RenderingD wait_semaphores[0] = signal_semaphore; } - frames[frame].semaphores_to_wait_on.clear(); + frames->get_current_frame().semaphores_to_wait_on.clear(); } void RenderingDevice::_execute_frame(bool p_present) { // Check whether this frame should present the swap chains and in which queue. - const bool frame_can_present = p_present && !frames[frame].swap_chains_to_present.is_empty(); + const bool frame_can_present = p_present && !frames->get_current_frame().swap_chains_to_present.is_empty(); const bool separate_present_queue = main_queue != present_queue; // The semaphore is required if the frame can be presented and a separate present queue is used; // since the separate queue will wait for that semaphore before presenting. const RDD::SemaphoreID semaphore = (frame_can_present && separate_present_queue) - ? frames[frame].semaphore + ? frames->get_current_frame().semaphore : RDD::SemaphoreID(nullptr); const bool present_swap_chain = frame_can_present && !separate_present_queue; - execute_chained_cmds(present_swap_chain, frames[frame].fence, semaphore); + execute_chained_cmds(present_swap_chain, frames->get_current_frame().fence, semaphore); // Indicate the fence has been signaled so the next time the frame's contents need to be // used, the CPU needs to wait on the work to be completed. - frames[frame].fence_signaled = true; + frames->get_current_frame().fence_signaled = true; + frames->update(p_present); if (frame_can_present) { if (separate_present_queue) { // Issue the presentation separately if the presentation queue is different from the main queue. - driver->command_queue_execute_and_present(present_queue, frames[frame].semaphore, {}, {}, {}, frames[frame].swap_chains_to_present); + driver->command_queue_execute_and_present(present_queue, frames->get_current_frame().semaphore, {}, {}, {}, frames->get_current_frame().swap_chains_to_present); } - frames[frame].swap_chains_to_present.clear(); + frames->get_current_frame().swap_chains_to_present.clear(); } } void RenderingDevice::_stall_for_frame(uint32_t p_frame) { thread_local PackedByteArray packed_byte_array; - if (frames[p_frame].fence_signaled) { - driver->fence_wait(frames[p_frame].fence); - frames[p_frame].fence_signaled = false; + if (frames->get_frame(p_frame).fence_signaled) { + frames->frame_wait(p_frame); + frames->get_frame(p_frame).fence_signaled = false; // Flush any pending requests for asynchronous buffer downloads. - if (!frames[p_frame].download_buffer_get_data_requests.is_empty()) { - for (uint32_t i = 0; i < frames[p_frame].download_buffer_get_data_requests.size(); i++) { - const BufferGetDataRequest &request = frames[p_frame].download_buffer_get_data_requests[i]; + if (!frames->get_frame(p_frame).download_buffer_get_data_requests.is_empty()) { + for (uint32_t i = 0; i < frames->get_frame(p_frame).download_buffer_get_data_requests.size(); i++) { + const BufferGetDataRequest &request = frames->get_frame(p_frame).download_buffer_get_data_requests[i]; packed_byte_array.resize(request.size); uint32_t array_offset = 0; for (uint32_t j = 0; j < request.frame_local_count; j++) { uint32_t local_index = request.frame_local_index + j; - const RDD::BufferCopyRegion ®ion = frames[p_frame].download_buffer_copy_regions[local_index]; - uint8_t *buffer_data = driver->buffer_map(frames[p_frame].download_buffer_staging_buffers[local_index]); + const RDD::BufferCopyRegion ®ion = frames->get_frame(p_frame).download_buffer_copy_regions[local_index]; + uint8_t *buffer_data = driver->buffer_map(frames->get_frame(p_frame).download_buffer_staging_buffers[local_index]); memcpy(&packed_byte_array.write[array_offset], &buffer_data[region.dst_offset], region.size); - driver->buffer_unmap(frames[p_frame].download_buffer_staging_buffers[local_index]); + driver->buffer_unmap(frames->get_frame(p_frame).download_buffer_staging_buffers[local_index]); array_offset += region.size; } request.callback.call(packed_byte_array); } - frames[p_frame].download_buffer_staging_buffers.clear(); - frames[p_frame].download_buffer_copy_regions.clear(); - frames[p_frame].download_buffer_get_data_requests.clear(); + frames->get_frame(p_frame).download_buffer_staging_buffers.clear(); + frames->get_frame(p_frame).download_buffer_copy_regions.clear(); + frames->get_frame(p_frame).download_buffer_get_data_requests.clear(); } // Flush any pending requests for asynchronous texture downloads. - if (!frames[p_frame].download_texture_get_data_requests.is_empty()) { + if (!frames->get_frame(p_frame).download_texture_get_data_requests.is_empty()) { uint32_t pitch_step = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP); - for (uint32_t i = 0; i < frames[p_frame].download_texture_get_data_requests.size(); i++) { - const TextureGetDataRequest &request = frames[p_frame].download_texture_get_data_requests[i]; + for (uint32_t i = 0; i < frames->get_frame(p_frame).download_texture_get_data_requests.size(); i++) { + const TextureGetDataRequest &request = frames->get_frame(p_frame).download_texture_get_data_requests[i]; uint32_t texture_size = get_image_format_required_size(request.format, request.width, request.height, request.depth, request.mipmaps); packed_byte_array.resize(texture_size); @@ -6612,7 +6618,7 @@ void RenderingDevice::_stall_for_frame(uint32_t p_frame) { for (uint32_t j = 0; j < request.frame_local_count; j++) { uint32_t local_index = request.frame_local_index + j; - const RDD::BufferTextureCopyRegion ®ion = frames[p_frame].download_buffer_texture_copy_regions[local_index]; + const RDD::BufferTextureCopyRegion ®ion = frames->get_frame(p_frame).download_buffer_texture_copy_regions[local_index]; uint32_t w = STEPIFY(request.width >> region.texture_subresources.mipmap, block_w); uint32_t h = STEPIFY(request.height >> region.texture_subresources.mipmap, block_h); uint32_t region_w = MIN(region_size, w - region.texture_offset.x); @@ -6620,9 +6626,9 @@ void RenderingDevice::_stall_for_frame(uint32_t p_frame) { uint32_t region_pitch = (region_w * pixel_size * block_w) >> pixel_rshift; region_pitch = STEPIFY(region_pitch, pitch_step); - uint8_t *buffer_data = driver->buffer_map(frames[p_frame].download_texture_staging_buffers[local_index]); + uint8_t *buffer_data = driver->buffer_map(frames->get_frame(p_frame).download_texture_staging_buffers[local_index]); const uint8_t *read_ptr = buffer_data + region.buffer_offset; - uint8_t *write_ptr = packed_byte_array.ptrw() + frames[p_frame].download_texture_mipmap_offsets[local_index]; + uint8_t *write_ptr = packed_byte_array.ptrw() + frames->get_frame(p_frame).download_texture_mipmap_offsets[local_index]; uint32_t unit_size = pixel_size; if (block_w != 1 || block_h != 1) { unit_size = block_size; @@ -6635,22 +6641,22 @@ void RenderingDevice::_stall_for_frame(uint32_t p_frame) { read_ptr += region_pitch; } - driver->buffer_unmap(frames[p_frame].download_texture_staging_buffers[local_index]); + driver->buffer_unmap(frames->get_frame(p_frame).download_texture_staging_buffers[local_index]); } request.callback.call(packed_byte_array); } - frames[p_frame].download_texture_staging_buffers.clear(); - frames[p_frame].download_buffer_texture_copy_regions.clear(); - frames[p_frame].download_texture_mipmap_offsets.clear(); - frames[p_frame].download_texture_get_data_requests.clear(); + frames->get_frame(p_frame).download_texture_staging_buffers.clear(); + frames->get_frame(p_frame).download_buffer_texture_copy_regions.clear(); + frames->get_frame(p_frame).download_texture_mipmap_offsets.clear(); + frames->get_frame(p_frame).download_texture_get_data_requests.clear(); } } } void RenderingDevice::_stall_for_previous_frames() { - for (uint32_t i = 0; i < frames.size(); i++) { + for (uint32_t i = 0; i < frames->get_number_of_frames(); i++) { _stall_for_frame(i); } } @@ -6662,7 +6668,7 @@ void RenderingDevice::_flush_and_stall_for_all_frames() { _begin_frame(); } -Error RenderingDevice::initialize(RenderingContextDriver *p_context, DisplayServer::WindowID p_main_window) { +Error RenderingDevice::initialize(RenderingContextDriver *p_context, DisplayServer::WindowID p_main_window, bool p_monitored_frames) { ERR_RENDER_THREAD_GUARD_V(ERR_UNAVAILABLE); Error err; @@ -6707,7 +6713,16 @@ Error RenderingDevice::initialize(RenderingContextDriver *p_context, DisplayServ frame_count = MAX(2U, uint32_t(GLOBAL_GET("rendering/rendering_device/vsync/frame_queue_size"))); } - frame = 0; +#ifdef EXTERNAL_TARGET_ENABLED + if (p_monitored_frames) { + frames = new MonitoredFrames(driver, this); + } else +#endif + { + frames = new DefaultFrames(driver); + } + + frames->set_frame_index(0); max_timestamp_query_elements = GLOBAL_GET("debug/settings/profiler/max_timestamp_query_elements"); device = context->device_get(device_index); @@ -6776,58 +6791,59 @@ Error RenderingDevice::initialize(RenderingContextDriver *p_context, DisplayServ // Use the processor count as the max amount of transfer workers that can be created. transfer_worker_pool_max_size = OS::get_singleton()->get_processor_count(); - frames.resize(frame_count); + frames->resize(frame_count); // Create data for all the frames. - for (uint32_t i = 0; i < frames.size(); i++) { - frames[i].index = 0; + for (uint32_t i = 0; i < frames->get_number_of_frames(); i++) { + frames->get_frame(i).index = 0; // Create command pool, command buffers, semaphores and fences. - frames[i].command_pool = driver->command_pool_create(main_queue_family, RDD::COMMAND_BUFFER_TYPE_PRIMARY); - ERR_FAIL_COND_V(!frames[i].command_pool, FAILED); - frames[i].command_buffer = driver->command_buffer_create(frames[i].command_pool); - ERR_FAIL_COND_V(!frames[i].command_buffer, FAILED); - frames[i].semaphore = driver->semaphore_create(); - ERR_FAIL_COND_V(!frames[i].semaphore, FAILED); - frames[i].fence = driver->fence_create(); - ERR_FAIL_COND_V(!frames[i].fence, FAILED); - frames[i].fence_signaled = false; + frames->get_frame(i).command_pool = driver->command_pool_create(main_queue_family, RDD::COMMAND_BUFFER_TYPE_PRIMARY); + ERR_FAIL_COND_V(!frames->get_frame(i).command_pool, FAILED); + frames->get_frame(i).command_buffer = driver->command_buffer_create(frames->get_frame(i).command_pool); + ERR_FAIL_COND_V(!frames->get_frame(i).command_buffer, FAILED); + frames->get_frame(i).semaphore = driver->semaphore_create(); + ERR_FAIL_COND_V(!frames->get_frame(i).semaphore, FAILED); + frames->get_frame(i).fence = driver->fence_create(); + ERR_FAIL_COND_V(!frames->get_frame(i).fence, FAILED); + frames->get_frame(i).fence_signaled = false; // Create query pool. - frames[i].timestamp_pool = driver->timestamp_query_pool_create(max_timestamp_query_elements); - frames[i].timestamp_names.resize(max_timestamp_query_elements); - frames[i].timestamp_cpu_values.resize(max_timestamp_query_elements); - frames[i].timestamp_count = 0; - frames[i].timestamp_result_names.resize(max_timestamp_query_elements); - frames[i].timestamp_cpu_result_values.resize(max_timestamp_query_elements); - frames[i].timestamp_result_values.resize(max_timestamp_query_elements); - frames[i].timestamp_result_count = 0; + frames->get_frame(i).timestamp_pool = driver->timestamp_query_pool_create(max_timestamp_query_elements); + frames->get_frame(i).timestamp_names.resize(max_timestamp_query_elements); + frames->get_frame(i).timestamp_cpu_values.resize(max_timestamp_query_elements); + frames->get_frame(i).timestamp_count = 0; + frames->get_frame(i).timestamp_result_names.resize(max_timestamp_query_elements); + frames->get_frame(i).timestamp_cpu_result_values.resize(max_timestamp_query_elements); + frames->get_frame(i).timestamp_result_values.resize(max_timestamp_query_elements); + frames->get_frame(i).timestamp_result_count = 0; // Assign the main queue family and command pool to the command buffer pool. - frames[i].command_buffer_pool.pool = frames[i].command_pool; + frames->get_frame(i).command_buffer_pool.pool = frames->get_frame(i).command_pool; // Create the semaphores for the transfer workers. - frames[i].transfer_worker_semaphores.resize(transfer_worker_pool_max_size); + frames->get_frame(i).transfer_worker_semaphores.resize(transfer_worker_pool_max_size); for (uint32_t j = 0; j < transfer_worker_pool_max_size; j++) { - frames[i].transfer_worker_semaphores[j] = driver->semaphore_create(); - ERR_FAIL_COND_V(!frames[i].transfer_worker_semaphores[j], FAILED); + frames->get_frame(i).transfer_worker_semaphores[j] = driver->semaphore_create(); + ERR_FAIL_COND_V(!frames->get_frame(i).transfer_worker_semaphores[j], FAILED); } } // Start from frame count, so everything else is immediately old. - frames_drawn = frames.size(); + frames->set_frames_drawn(frames->get_number_of_frames()); // Initialize recording on the first frame. - driver->begin_segment(frame, frames_drawn++); - driver->command_buffer_begin(frames[0].command_buffer); + driver->begin_segment(frames->get_frame_index(), frames->get_frames_drawn()); + frames->increment_frames_drawn(); + driver->command_buffer_begin(frames->get_frame(0).command_buffer); // Create draw graph and start it initialized as well. - draw_graph.initialize(driver, device, &_render_pass_create_from_graph, frames.size(), main_queue_family, SECONDARY_COMMAND_BUFFERS_PER_FRAME); + draw_graph.initialize(driver, device, &_render_pass_create_from_graph, frames->get_number_of_frames(), main_queue_family, SECONDARY_COMMAND_BUFFERS_PER_FRAME); draw_graph.begin(); - for (uint32_t i = 0; i < frames.size(); i++) { + for (uint32_t i = 0; i < frames->get_number_of_frames(); i++) { // Reset all queries in a query pool before doing any operations with them.. - driver->command_timestamp_query_pool_reset(frames[0].command_buffer, frames[i].timestamp_pool, max_timestamp_query_elements); + driver->command_timestamp_query_pool_reset(frames->get_frame(0).command_buffer, frames->get_frame(i).timestamp_pool, max_timestamp_query_elements); } // Convert block size from KB. @@ -6860,7 +6876,7 @@ Error RenderingDevice::initialize(RenderingContextDriver *p_context, DisplayServ download_staging_buffers.used = false; download_staging_buffers.usage_bits = RDD::BUFFER_USAGE_TRANSFER_TO_BIT; - for (uint32_t i = 0; i < frames.size(); i++) { + for (uint32_t i = 0; i < frames->get_number_of_frames(); i++) { // Staging was never used, create the blocks. err = _insert_staging_block(upload_staging_buffers); ERR_FAIL_COND_V(err, FAILED); @@ -6894,9 +6910,19 @@ Error RenderingDevice::initialize(RenderingContextDriver *p_context, DisplayServ // Find the best method available for VRS on the current hardware. _vrs_detect_method(); + frames->initialize(); + return OK; } +RenderingContextDriver *RenderingDevice::get_context() { + return context; +} + +RenderingDeviceDriver *RenderingDevice::get_driver() { + return driver; +} + Vector RenderingDevice::_load_pipeline_cache() { DirAccess::make_dir_recursive_absolute(pipeline_cache_file_path.get_base_dir()); @@ -6996,13 +7022,13 @@ void RenderingDevice::capture_timestamp(const String &p_name) { ERR_FAIL_COND_MSG(draw_list.active && draw_list.state.draw_count > 0, "Capturing timestamps during draw list creation is not allowed. Offending timestamp was: " + p_name); ERR_FAIL_COND_MSG(compute_list.active && compute_list.state.dispatch_count > 0, "Capturing timestamps during compute list creation is not allowed. Offending timestamp was: " + p_name); - ERR_FAIL_COND_MSG(frames[frame].timestamp_count >= max_timestamp_query_elements, vformat("Tried capturing more timestamps than the configured maximum (%d). You can increase this limit in the project settings under 'Debug/Settings' called 'Max Timestamp Query Elements'.", max_timestamp_query_elements)); + ERR_FAIL_COND_MSG(frames->get_current_frame().timestamp_count >= max_timestamp_query_elements, vformat("Tried capturing more timestamps than the configured maximum (%d). You can increase this limit in the project settings under 'Debug/Settings' called 'Max Timestamp Query Elements'.", max_timestamp_query_elements)); - draw_graph.add_capture_timestamp(frames[frame].timestamp_pool, frames[frame].timestamp_count); + draw_graph.add_capture_timestamp(frames->get_current_frame().timestamp_pool, frames->get_current_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++; + frames->get_current_frame().timestamp_names[frames->get_current_frame().timestamp_count] = p_name; + frames->get_current_frame().timestamp_cpu_values[frames->get_current_frame().timestamp_count] = OS::get_singleton()->get_ticks_usec(); + frames->get_current_frame().timestamp_count++; } uint64_t RenderingDevice::get_driver_resource(DriverResource p_resource, RID p_rid, uint64_t p_index) { @@ -7123,29 +7149,29 @@ uint64_t RenderingDevice::get_device_allocs_by_object_type(uint32_t type) const uint32_t RenderingDevice::get_captured_timestamps_count() const { ERR_RENDER_THREAD_GUARD_V(0); - return frames[frame].timestamp_result_count; + return frames->query_current_frame().timestamp_result_count; } uint64_t RenderingDevice::get_captured_timestamps_frame() const { ERR_RENDER_THREAD_GUARD_V(0); - return frames[frame].index; + return frames->query_current_frame().index; } uint64_t RenderingDevice::get_captured_timestamp_gpu_time(uint32_t p_index) const { ERR_RENDER_THREAD_GUARD_V(0); - ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0); - return driver->timestamp_query_result_to_time(frames[frame].timestamp_result_values[p_index]); + ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames->query_current_frame().timestamp_result_count, 0); + return driver->timestamp_query_result_to_time(frames->get_current_frame().timestamp_result_values[p_index]); } uint64_t RenderingDevice::get_captured_timestamp_cpu_time(uint32_t p_index) const { ERR_RENDER_THREAD_GUARD_V(0); - ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0); - return frames[frame].timestamp_cpu_result_values[p_index]; + ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames->query_current_frame().timestamp_result_count, 0); + return frames->query_current_frame().timestamp_cpu_result_values[p_index]; } String RenderingDevice::get_captured_timestamp_name(uint32_t p_index) const { - ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, String()); - return frames[frame].timestamp_result_names[p_index]; + ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames->query_current_frame().timestamp_result_count, String()); + return frames->query_current_frame().timestamp_result_names[p_index]; } uint64_t RenderingDevice::limit_get(Limit p_limit) const { @@ -7155,7 +7181,7 @@ uint64_t RenderingDevice::limit_get(Limit p_limit) const { void RenderingDevice::finalize() { ERR_RENDER_THREAD_GUARD(); - if (!frames.is_empty()) { + if (!frames->is_empty()) { // Wait for all frames to have finished rendering. _flush_and_stall_for_all_frames(); } @@ -7220,21 +7246,21 @@ void RenderingDevice::finalize() { _free_transfer_workers(); // Free everything pending. - for (uint32_t i = 0; i < frames.size(); i++) { - int f = (frame + i) % frames.size(); + for (uint32_t i = 0; i < frames->get_number_of_frames(); i++) { + int f = (frames->get_frame_index() + i) % frames->get_number_of_frames(); _free_pending_resources(f); - driver->command_pool_free(frames[i].command_pool); - driver->timestamp_query_pool_free(frames[i].timestamp_pool); - driver->semaphore_free(frames[i].semaphore); - driver->fence_free(frames[i].fence); + driver->command_pool_free(frames->get_frame(i).command_pool); + driver->timestamp_query_pool_free(frames->get_frame(i).timestamp_pool); + driver->semaphore_free(frames->get_frame(i).semaphore); + driver->fence_free(frames->get_frame(i).fence); - RDG::CommandBufferPool &buffer_pool = frames[i].command_buffer_pool; + RDG::CommandBufferPool &buffer_pool = frames->get_frame(i).command_buffer_pool; for (uint32_t j = 0; j < buffer_pool.buffers.size(); j++) { driver->semaphore_free(buffer_pool.semaphores[j]); } - for (uint32_t j = 0; j < frames[i].transfer_worker_semaphores.size(); j++) { - driver->semaphore_free(frames[i].transfer_worker_semaphores[j]); + for (uint32_t j = 0; j < frames->get_frame(i).transfer_worker_semaphores.size(); j++) { + driver->semaphore_free(frames->get_frame(i).transfer_worker_semaphores[j]); } } @@ -7243,7 +7269,8 @@ void RenderingDevice::finalize() { driver->pipeline_cache_free(); } - frames.clear(); + frames->clear(); + delete frames; for (int i = 0; i < upload_staging_buffers.blocks.size(); i++) { driver->buffer_free(upload_staging_buffers.blocks[i].driver_id); diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index b6e589e714da..dd98436ae811 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -1200,6 +1200,7 @@ class RenderingDevice : public RenderingDeviceCommons { int screen_get_height(DisplayServer::WindowID p_screen = DisplayServer::MAIN_WINDOW_ID) const; int screen_get_pre_rotation_degrees(DisplayServer::WindowID p_screen = DisplayServer::MAIN_WINDOW_ID) const; FramebufferFormatID screen_get_framebuffer_format(DisplayServer::WindowID p_screen = DisplayServer::MAIN_WINDOW_ID) const; + RDD::SwapChainID screen_get_swapchain(DisplayServer::WindowID p_screen); Error screen_free(DisplayServer::WindowID p_screen = DisplayServer::MAIN_WINDOW_ID); /*************************/ @@ -1556,9 +1557,254 @@ class RenderingDevice : public RenderingDeviceCommons { uint32_t max_timestamp_query_elements = 0; - int frame = 0; - TightLocalVector frames; - uint64_t frames_drawn = 0; + class Frames { + protected: + int frame = 0; + TightLocalVector frames; + uint64_t frames_drawn = 0; + RenderingDeviceDriver *driver = nullptr; + + public: + int get_frame_index() const { + return frame; + } + + void set_frame_index(int p_index) { + frame = p_index; + } + + uint32_t get_number_of_frames() const { + return frames.size(); + } + + bool is_empty() const { + return frames.is_empty(); + } + + Frame query_current_frame() const { + return frames[frame]; + } + + Frame &get_current_frame() { + return frames[frame]; + } + + Frame &get_frame(uint32_t p_index) { + return frames[p_index]; + } + + uint64_t get_frames_drawn() const { + return frames_drawn; + } + + void set_frames_drawn(uint64_t p_frames_drawn) { + frames_drawn = p_frames_drawn; + } + + void increment_frames_drawn() { + frames_drawn++; + } + + virtual void resize(uint32_t p_size) = 0; + + void clear() { + frames.clear(); + } + + virtual void frame_wait(uint32_t p_index) = 0; + + virtual void update(bool p_frame_completed) = 0; + + virtual void initialize() = 0; + + Frames() {} + Frames(RenderingDeviceDriver *p_driver) { + driver = p_driver; + } + virtual ~Frames() = default; + }; + + class DefaultFrames : public Frames { + public: + virtual void resize(uint32_t p_size) override final { + frames.resize(p_size); + } + + virtual void frame_wait(uint32_t p_index) override final { + driver->fence_wait(frames[p_index].fence); + driver->frame_cleanup(frames[p_index].fence); + } + + virtual void update(bool p_frame_completed) override final {} + + virtual void initialize() override final {} + + DefaultFrames(RenderingDeviceDriver *p_driver) : + Frames(p_driver) {} + }; + +#ifdef EXTERNAL_TARGET_ENABLED + class MonitoredFrames; + + struct FenceData { + int frame_index = 0; + HashMap window_buffers; + HashMap swapchain_versions; + ConditionVariable fence_set_cond; + ConditionVariable fence_waited_cond; + BinaryMutex fence_mutex; + bool fence_set = false; + bool fence_waited = false; + MonitoredFrames *context; + bool frame_completed = true; + }; + + class MonitoredFrames : public Frames { + Thread monitor_thread; + TightLocalVector fence_data; + RenderingDevice *context; + bool stop_fence_callback = false; + + static void _monitor(MonitoredFrames *p_context) { + int frame_to_wait = 0; + + bool stop = false; + while (!stop) { + { + MutexLock lock(p_context->fence_data[frame_to_wait].fence_mutex); + while (!p_context->fence_data[frame_to_wait].fence_set) { + p_context->fence_data[frame_to_wait].fence_set_cond.wait(lock); + + if (stop) { + return; + } + } + p_context->fence_data[frame_to_wait].fence_set = false; + } + + p_context->driver->fence_wait(p_context->frames[frame_to_wait].fence); + + if (p_context->fence_data[frame_to_wait].frame_completed) { + { + MutexLock lock(p_context->fence_data[frame_to_wait].fence_mutex); + + for (KeyValue &E : p_context->fence_data[frame_to_wait].window_buffers) { + const DisplayServer::WindowID &id = E.key; + const uint32_t &buffer = E.value; + + const RDD::SwapChainID swapchain_id = p_context->context->screen_swap_chains.find(id)->value; + + MutexLock external_lock(*p_context->driver->swap_chain_get_mutex(swapchain_id)); + + if (p_context->fence_data[frame_to_wait].swapchain_versions[id] == p_context->driver->swap_chain_get_version(swapchain_id)) { + p_context->driver->swap_chain_set_last_drawn_buffer(swapchain_id, buffer); + p_context->driver->swap_chain_set_frame_in_use(swapchain_id, buffer, false); + } + } + p_context->fence_data[frame_to_wait].window_buffers.clear(); + p_context->fence_data[frame_to_wait].swapchain_versions.clear(); + + p_context->fence_data[frame_to_wait].fence_waited = false; + p_context->fence_data[frame_to_wait].fence_waited_cond.notify_all(); + } + + frame_to_wait += 1; + frame_to_wait %= p_context->fence_data.size(); + } else { + MutexLock lock(p_context->fence_data[frame_to_wait].fence_mutex); + + p_context->fence_data[frame_to_wait].fence_waited = false; + p_context->fence_data[frame_to_wait].fence_waited_cond.notify_all(); + } + + stop = p_context->stop_fence_callback; + } + } + + public: + virtual void resize(uint32_t p_size) override final { + frames.resize(p_size); + fence_data.resize(p_size); + } + + virtual void frame_wait(uint32_t p_index) override final { + MutexLock lock(fence_data[frame].fence_mutex); + + while (fence_data[frame].fence_waited) { + fence_data[frame].fence_waited_cond.wait(lock); + } + + driver->frame_cleanup(frames[p_index].fence); + } + + virtual void update(bool p_frame_completed) override final { + MutexLock lock(fence_data[frame].fence_mutex); + while (fence_data[frame].fence_waited) { + fence_data[frame].fence_waited_cond.wait(lock); + } + + fence_data[frame].context = this; + fence_data[frame].frame_index = frame; + fence_data[frame].frame_completed = p_frame_completed; + + fence_data[frame].window_buffers.clear(); + + if (p_frame_completed) { + for (KeyValue &E : context->screen_swap_chains) { + const DisplayServer::WindowID &id = E.key; + const RDD::SwapChainID &swapchain_id = E.value; + + MutexLock external_lock(*driver->swap_chain_get_mutex(swapchain_id)); + + fence_data[frame].window_buffers.insert(id, driver->swap_chain_get_image_index(swapchain_id)); + } + + { + fence_data[frame].swapchain_versions.clear(); + for (KeyValue &E : context->screen_swap_chains) { + const DisplayServer::WindowID &id = E.key; + const RDD::SwapChainID swapchain_id = E.value; + + MutexLock external_lock(*driver->swap_chain_get_mutex(swapchain_id)); + + fence_data[frame].swapchain_versions.insert(id, driver->swap_chain_get_version(swapchain_id)); + } + } + } + + fence_data[frame].fence_waited = true; + fence_data[frame].fence_set = true; + fence_data[frame].fence_set_cond.notify_all(); + } + + virtual void initialize() override final { + monitor_thread.start([](void *p_user) { + MonitoredFrames::_monitor((MonitoredFrames *)p_user); + }, + this); + } + + MonitoredFrames() {} + MonitoredFrames(RenderingDeviceDriver *p_driver, RenderingDevice *p_context) : + Frames(p_driver) { + context = p_context; + } + + ~MonitoredFrames() { + stop_fence_callback = true; + + for (uint32_t i = 0; i < fence_data.size(); i++) { + MutexLock lock(fence_data[i].fence_mutex); + fence_data[i].fence_set = true; + fence_data[i].fence_set_cond.notify_all(); + } + + monitor_thread.wait_to_finish(); + } + }; +#endif + + Frames *frames; // Whenever logic/physics request a graphics operation (not just deleting a resource) that requires // us to flush all graphics commands, we must set frames_pending_resources_for_processing = frames.size(). @@ -1578,7 +1824,7 @@ class RenderingDevice : public RenderingDeviceCommons { protected: void execute_chained_cmds(bool p_present_swap_chain, - RenderingDeviceDriver::FenceID p_draw_fence, + RenderingDeviceDriver::FenceID p_fence, RenderingDeviceDriver::SemaphoreID p_dst_draw_semaphore_to_signal); public: @@ -1598,7 +1844,11 @@ class RenderingDevice : public RenderingDeviceCommons { #endif public: - Error initialize(RenderingContextDriver *p_context, DisplayServer::WindowID p_main_window = DisplayServer::INVALID_WINDOW_ID); + Error initialize(RenderingContextDriver *p_context, DisplayServer::WindowID p_main_window = DisplayServer::INVALID_WINDOW_ID, bool p_monitored_frames = false); + + RenderingContextDriver *get_context(); + RenderingDeviceDriver *get_driver(); + void finalize(); void _set_max_fps(int p_max_fps); diff --git a/servers/rendering/rendering_device_driver.h b/servers/rendering/rendering_device_driver.h index 8a3814145a29..2a375e240042 100644 --- a/servers/rendering/rendering_device_driver.h +++ b/servers/rendering/rendering_device_driver.h @@ -376,6 +376,7 @@ class RenderingDeviceDriver : public RenderingDeviceCommons { virtual FenceID fence_create() = 0; virtual Error fence_wait(FenceID p_fence) = 0; + virtual void frame_cleanup(FenceID p_fence) = 0; virtual void fence_free(FenceID p_fence) = 0; /********************/ @@ -452,6 +453,26 @@ class RenderingDeviceDriver : public RenderingDeviceCommons { // Android uses this with Swappy library. Some implementations or platforms may ignore this hint. virtual void swap_chain_set_max_fps(SwapChainID p_swap_chain, int p_max_fps) {} +#ifdef EXTERNAL_TARGET_ENABLED + // Retrieve a swap chain's mutex. + virtual BinaryMutex *swap_chain_get_mutex(SwapChainID p_swap_chain) { return nullptr; } + + // Set whether a frame is currently used by a swap chain or not. + virtual void swap_chain_set_frame_in_use(SwapChainID p_swap_chain, size_t p_index, bool p_in_use) {} + + // Retrieve the buffer of the last drawn frame. + virtual int swap_chain_get_last_drawn_buffer(SwapChainID p_swap_chain) { return -1; } + + // Update the buffer of the last drawn frame. + virtual void swap_chain_set_last_drawn_buffer(SwapChainID p_swap_chain, int p_buffer) {} + + // Retrieve the index of the currently drawn frame. + virtual uint32_t swap_chain_get_image_index(SwapChainID p_swap_chain) { return 0; } + + // Retrieve swap chain version. + virtual uint64_t swap_chain_get_version(SwapChainID p_swap_chain) { return 0; } +#endif + // Wait until all rendering associated to the swap chain is finished before deleting it. virtual void swap_chain_free(SwapChainID p_swap_chain) = 0; diff --git a/servers/rendering/rendering_native_surface.cpp b/servers/rendering/rendering_native_surface.cpp new file mode 100644 index 000000000000..9600beaf111f --- /dev/null +++ b/servers/rendering/rendering_native_surface.cpp @@ -0,0 +1,45 @@ +/**************************************************************************/ +/* rendering_native_surface.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_native_surface.h" + +void RenderingNativeSurface::_bind_methods() { +} + +RenderingNativeSurface::RenderingNativeSurface() { +} + +RenderingNativeSurface::~RenderingNativeSurface() { +} + +#ifdef EXTERNAL_TARGET_ENABLED +void RenderingNativeSurface::setup_external_swapchain_callbacks() { +} +#endif diff --git a/servers/rendering/rendering_native_surface.h b/servers/rendering/rendering_native_surface.h new file mode 100644 index 000000000000..f4a9c6396d76 --- /dev/null +++ b/servers/rendering/rendering_native_surface.h @@ -0,0 +1,57 @@ +/**************************************************************************/ +/* rendering_native_surface.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. */ +/**************************************************************************/ + +#pragma once + +#include "core/object/class_db.h" +#include "core/object/ref_counted.h" + +class RenderingContextDriver; +class GLManager; + +class RenderingNativeSurface : public RefCounted { + GDCLASS(RenderingNativeSurface, RefCounted); + + static void _bind_methods(); + +public: + RenderingNativeSurface(); + ~RenderingNativeSurface(); + +#ifdef EXTERNAL_TARGET_ENABLED + virtual void setup_external_swapchain_callbacks(); +#endif + + virtual RenderingContextDriver *create_rendering_context(const String &p_driver_name) = 0; + + virtual GLManager *create_gl_manager(const String &p_driver_name) { return nullptr; } + + virtual void *get_native_id() const = 0; +}; diff --git a/servers/rendering/rendering_native_surface_external_target.cpp b/servers/rendering/rendering_native_surface_external_target.cpp new file mode 100644 index 000000000000..84e3d3b5fe3c --- /dev/null +++ b/servers/rendering/rendering_native_surface_external_target.cpp @@ -0,0 +1,442 @@ +/**************************************************************************/ +/* rendering_native_surface_external_target.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 "servers/rendering/rendering_native_surface_external_target.h" + +#include "servers/display_server_embedded.h" +#include "servers/rendering/rendering_device.h" + +#ifdef EXTERNAL_TARGET_ENABLED + +#ifdef VULKAN_ENABLED +#include "drivers/vulkan/rendering_device_driver_vulkan.h" +#endif + +#if defined(GLES3_ENABLED) +#include "platform_gl.h" +#endif + +struct WindowData { +#if defined(GLES3_ENABLED) + uint32_t backingWidth; + uint32_t backingHeight; + GLuint viewFramebuffer; + GLuint colorTexture; + GLuint depthTexture; +#endif +}; + +class GLManagerExternal : public GLManager { +public: + void set_surface(Ref p_surface); +#ifdef GLES3_ENABLED + void set_opengl_callbacks(Callable p_make_current, Callable p_done_current, uint64_t p_get_proc_address); +#endif + virtual Error initialize(void *p_native_display = nullptr) override; + virtual Error open_display(void *p_native_display = nullptr) override { return OK; } + Error window_create(DisplayServer::WindowID p_id, Ref p_native_surface, int p_width, int p_height) override; + virtual void window_resize(DisplayServer::WindowID p_id, int p_width, int p_height) override; + virtual void window_make_current(DisplayServer::WindowID p_id) override; + virtual void release_current() override {} + virtual void swap_buffers() override; + virtual void window_destroy(DisplayServer::WindowID p_id) override; + virtual Size2i window_get_size(DisplayServer::WindowID p_id) override; + void deinitialize(); + virtual int window_get_render_target(DisplayServer::WindowID p_id) const override; + virtual int window_get_color_texture(DisplayServer::WindowID p_id) const override; + + virtual void set_use_vsync(bool p_use) override {} + virtual bool is_using_vsync() const override { return false; } + + GLManagerExternal() {} + ~GLManagerExternal() { + deinitialize(); + } + +private: + Ref surface; + HashMap windows; + HashMap> window_surface_map; + HashMap, DisplayServer::WindowID> surface_window_map; + DisplayServer::WindowID current_window = -1; +#if defined(GLES3_ENABLED) + Callable make_current; + Callable done_current; +#ifdef GLAD_ENABLED + GLADloadfunc get_proc_address = nullptr; +#endif +#endif +}; + +void GLManagerExternal::set_surface(Ref p_surface) { + surface = p_surface; +} + +#ifdef GLES3_ENABLED +void GLManagerExternal::set_opengl_callbacks(Callable p_make_current, Callable p_done_current, uint64_t p_get_proc_address) { + make_current = p_make_current; + done_current = p_done_current; +#ifdef GLAD_ENABLED + get_proc_address = (GLADloadfunc)p_get_proc_address; +#endif +} +#endif + +Error GLManagerExternal::initialize(void *p_native_display) { +#ifdef GLES3_ENABLED +#ifdef GLAD_ENABLED + RasterizerGLES3::preloadGL(get_proc_address); +#endif + + make_current.call(); +#endif + return OK; +} + +Error GLManagerExternal::window_create(DisplayServer::WindowID p_id, Ref p_native_surface, int p_width, int p_height) { + Ref external_surface = Object::cast_to(*p_native_surface); + if (!external_surface.is_valid()) { + ERR_PRINT("Given surface is not RenderingNativeSurfaceExternalTarget."); + return FAILED; + } + +#if defined(GLES3_ENABLED) + WindowData &gles_data = windows[p_id]; + gles_data.backingWidth = surface->get_width(); + gles_data.backingHeight = surface->get_height(); + + make_current.call(); + + // Generate Framebuffer. + glGenFramebuffers(1, &gles_data.viewFramebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, gles_data.viewFramebuffer); + + // Bind color texture. + glGenTextures(1, &gles_data.colorTexture); + glBindTexture(GL_TEXTURE_2D, gles_data.colorTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, gles_data.backingWidth, gles_data.backingHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gles_data.colorTexture, 0); + + // Bind depth texture. + glGenTextures(1, &gles_data.depthTexture); + glBindTexture(GL_TEXTURE_2D, gles_data.depthTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, gles_data.backingWidth, gles_data.backingHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, gles_data.depthTexture, 0); + + // Check if framebuffer has been created successfully. + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + ERR_PRINT(vformat("failed to make complete framebuffer object: code %d", glCheckFramebufferStatus(GL_FRAMEBUFFER))); + return FAILED; + } + + surface_window_map[external_surface] = p_id; + window_surface_map[p_id] = external_surface; +#endif + return OK; +} + +void GLManagerExternal::window_resize(DisplayServer::WindowID p_id, int p_width, int p_height) { + ERR_FAIL_COND(!windows.has(p_id)); + WindowData &gles_data = windows[p_id]; +#if defined(GLES3_ENABLED) + make_current.call(); + window_destroy(p_id); + surface->resize(Size2i(p_width, p_height)); + window_create(p_id, surface, p_width, p_height); +#endif +} + +void GLManagerExternal::window_make_current(DisplayServer::WindowID p_id) { + ERR_FAIL_COND(!windows.has(p_id)); + WindowData &gles_data = windows[p_id]; +#if defined(GLES3_ENABLED) + make_current.call(); + glBindFramebuffer(GL_FRAMEBUFFER, gles_data.viewFramebuffer); + current_window = p_id; +#endif +} + +void GLManagerExternal::swap_buffers() { + ERR_FAIL_COND(!windows.has(current_window)); +#if defined(GLES3_ENABLED) + make_current.call(); +#ifdef DEBUG_ENABLED + GLenum err = glGetError(); + if (err) { + ERR_PRINT(vformat("DrawView: %d error", err)); + } +#endif +#endif +} + +void GLManagerExternal::window_destroy(DisplayServer::WindowID p_id) { + ERR_FAIL_COND(!windows.has(p_id)); + WindowData &gles_data = windows[p_id]; +#if defined(GLES3_ENABLED) + make_current.call(); + + glDeleteFramebuffers(1, &gles_data.viewFramebuffer); + gles_data.viewFramebuffer = 0; + + glDeleteTextures(1, &gles_data.colorTexture); + gles_data.colorTexture = 0; + + if (gles_data.depthTexture) { + glDeleteTextures(1, &gles_data.depthTexture); + gles_data.depthTexture = 0; + } + + Ref external_surface = window_surface_map[p_id]; + surface_window_map.erase(external_surface); + window_surface_map.erase(p_id); +#endif + windows.erase(p_id); +} + +Size2i GLManagerExternal::window_get_size(DisplayServer::WindowID p_id) { + ERR_FAIL_COND_V(!windows.has(p_id), Size2i()); + const WindowData &gles_data = windows[p_id]; +#if defined(GLES3_ENABLED) + return Size2i(surface->get_width(), surface->get_height()); +#else + return Size2i(); +#endif +} + +void GLManagerExternal::deinitialize() { +#if defined(GLES3_ENABLED) + done_current.call(); +#endif +} + +int GLManagerExternal::window_get_render_target(DisplayServer::WindowID p_id) const { + ERR_FAIL_COND_V(!windows.has(p_id), 0); + const WindowData &gles_data = windows[p_id]; +#if defined(GLES3_ENABLED) + return gles_data.viewFramebuffer; +#else + return 0; +#endif +} + +int GLManagerExternal::window_get_color_texture(DisplayServer::WindowID p_id) const { + ERR_FAIL_COND_V(!windows.has(p_id), -1); + const WindowData &gles_data = windows[p_id]; +#if defined(GLES3_ENABLED) + return gles_data.colorTexture; +#else + return -1; +#endif +} + +void RenderingNativeSurfaceExternalTarget::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_width"), &RenderingNativeSurfaceExternalTarget::get_width); + ClassDB::bind_method(D_METHOD("get_height"), &RenderingNativeSurfaceExternalTarget::get_height); + ClassDB::bind_method(D_METHOD("get_window"), &RenderingNativeSurfaceExternalTarget::get_window); + + ClassDB::bind_static_method("RenderingNativeSurfaceExternalTarget", D_METHOD("create", "rendering_driver", "initial_size"), &RenderingNativeSurfaceExternalTarget::create_api); + + ClassDB::bind_method(D_METHOD("set_external_swapchain_callbacks", "images_created", "images_released"), &RenderingNativeSurfaceExternalTarget::set_external_swapchain_callbacks); + ClassDB::bind_method(D_METHOD("resize", "new_size"), &RenderingNativeSurfaceExternalTarget::resize); + ClassDB::bind_method(D_METHOD("acquire_next_image"), &RenderingNativeSurfaceExternalTarget::acquire_next_image); + ClassDB::bind_method(D_METHOD("release_image", "index"), &RenderingNativeSurfaceExternalTarget::release_image); + +#ifdef GLES3_ENABLED + ClassDB::bind_method(D_METHOD("set_opengl_callbacks", "make_current", "done_current", "get_proc_address"), &RenderingNativeSurfaceExternalTarget::set_opengl_callbacks); +#endif + ClassDB::bind_method(D_METHOD("get_frame_texture", "window_id"), &RenderingNativeSurfaceExternalTarget::get_frame_texture); +} + +#ifdef VULKAN_ENABLED +RenderingDeviceDriverVulkan *get_rendering_device_driver() { + RenderingDeviceDriverVulkan *driver = (RenderingDeviceDriverVulkan *)RenderingDevice::get_singleton()->get_driver(); + + return driver; +} + +RDD::SwapChainID get_swapchain(RenderingContextDriver::SurfaceID p_surface) { + RenderingDevice *rendering_device = RenderingDevice::get_singleton(); + RenderingContextDriverVulkan *context = (RenderingContextDriverVulkan *)rendering_device->get_context(); + DisplayServer::WindowID window = context->window_get_from_surface(p_surface); + + ERR_FAIL_COND_V_MSG(window == DisplayServer::INVALID_WINDOW_ID, RDD::SwapChainID(), "Window not set for this surface."); + + RDD::SwapChainID swapchain = rendering_device->screen_get_swapchain(window); + + return swapchain; +} +#endif + +uint32_t RenderingNativeSurfaceExternalTarget::get_width() const { + return width; +} + +uint32_t RenderingNativeSurfaceExternalTarget::get_height() const { + return height; +} + +DisplayServer::WindowID RenderingNativeSurfaceExternalTarget::get_window() { + DisplayServer::WindowID window = DisplayServer::INVALID_WINDOW_ID; + +#ifdef VULKAN_ENABLED + if (rendering_driver == "vulkan") { + RenderingDevice *rendering_device = RenderingDevice::get_singleton(); + RenderingContextDriverVulkan *context = (RenderingContextDriverVulkan *)rendering_device->get_context(); + window = context->window_get_from_surface(surface); + } +#endif +#ifdef GLES3_ENABLED + if (rendering_driver == "opengl3") { + window = DisplayServerEmbedded::get_singleton()->get_native_surface_window_id(Ref(this)); + } +#endif + + return window; +} + +void RenderingNativeSurfaceExternalTarget::set_surface(RenderingContextDriver::SurfaceID p_surface) { + ERR_FAIL_COND_MSG(p_surface == -1, "Invalid surface given."); + + surface = p_surface; +} + +RenderingContextDriver::SurfaceID RenderingNativeSurfaceExternalTarget::get_surface_id() { + return surface; +} + +Ref RenderingNativeSurfaceExternalTarget::create_api(String p_rendering_driver, Size2i p_initial_size) { + Ref result = nullptr; +#ifdef VULKAN_ENABLED + result = create(p_rendering_driver, p_initial_size); +#endif + return result; +} + +#ifdef VULKAN_ENABLED +Ref RenderingNativeSurfaceExternalTarget::create(String p_rendering_driver, Size2i p_initial_size) { + Ref result(memnew(RenderingNativeSurfaceExternalTarget(p_rendering_driver, p_initial_size.width, p_initial_size.height))); + return result; +} +#endif + +RenderingContextDriver *RenderingNativeSurfaceExternalTarget::create_rendering_context(const String &p_driver_name) { +#if defined(VULKAN_ENABLED) + return memnew(RenderingContextDriverVulkan); +#else + return nullptr; +#endif +} + +void RenderingNativeSurfaceExternalTarget::setup_external_swapchain_callbacks() { +#ifdef VULKAN_ENABLED + RenderingDeviceDriverVulkan *driver = get_rendering_device_driver(); + RDD::SwapChainID swapchain = get_swapchain(surface); + + ERR_FAIL_COND_MSG(swapchain == RDD::SwapChainID(), "Swapchain not set for this surface."); + + driver->external_swap_chain_set_callbacks(swapchain, post_images_created_callback, pre_images_released_callback); +#endif +} + +void RenderingNativeSurfaceExternalTarget::set_external_swapchain_callbacks(Callable p_images_created, Callable p_images_released) { + // NOTE: p_images_created: host wraps godot's swapchain images into qsgvulkantextures usable by the host + // NOTE: p_images_released: host frees all it's qsgvulkantextures + + post_images_created_callback = p_images_created; + pre_images_released_callback = p_images_released; +} + +void RenderingNativeSurfaceExternalTarget::resize(Size2i p_new_size) { + width = p_new_size.x; + height = p_new_size.y; + +#ifdef VULKAN_ENABLED + if (rendering_driver == "vulkan") { + RenderingDevice *rendering_device = RenderingDevice::get_singleton(); + RenderingContextDriverVulkan *context = (RenderingContextDriverVulkan *)rendering_device->get_context(); + context->surface_set_size(surface, p_new_size.x, p_new_size.y); + } +#endif +} + +int RenderingNativeSurfaceExternalTarget::acquire_next_image() { +#ifdef VULKAN_ENABLED + RenderingDeviceDriverVulkan *driver = get_rendering_device_driver(); + RDD::SwapChainID swapchain = get_swapchain(surface); + + ERR_FAIL_COND_V_MSG(swapchain == RDD::SwapChainID(), -1, "Swapchain not set for this surface."); + + int acquired_buffer_index = driver->external_swap_chain_grab_image(swapchain); + return acquired_buffer_index; +#endif +} + +void RenderingNativeSurfaceExternalTarget::release_image(int p_index) { +#ifdef VULKAN_ENABLED + RenderingDeviceDriverVulkan *driver = get_rendering_device_driver(); + RDD::SwapChainID swapchain = get_swapchain(surface); + + ERR_FAIL_COND_MSG(swapchain == RDD::SwapChainID(), "Swapchain not set for this surface."); + + driver->external_swap_chain_release_image(swapchain, p_index); +#endif +} + +#ifdef GLES3_ENABLED +void RenderingNativeSurfaceExternalTarget::set_opengl_callbacks(Callable p_make_current, Callable p_done_current, uint64_t p_get_proc_address) { + make_current = p_make_current; + done_current = p_done_current; + get_proc_address = p_get_proc_address; +} +#endif + +GLManager *RenderingNativeSurfaceExternalTarget::create_gl_manager(const String &p_driver_name) { +#if defined(GLES3_ENABLED) + GLManagerExternal *gl_manager = memnew(GLManagerExternal); + gl_manager->set_surface(Ref(this)); + gl_manager->set_opengl_callbacks(make_current, done_current, get_proc_address); + return (GLManager *)gl_manager; +#else + return nullptr; +#endif +} + +uint32_t RenderingNativeSurfaceExternalTarget::get_frame_texture(DisplayServer::WindowID p_window_id) const { + return DisplayServer::get_singleton()->window_get_native_handle(DisplayServer::WINDOW_HANDLE, p_window_id); +} + +RenderingNativeSurfaceExternalTarget::RenderingNativeSurfaceExternalTarget(String p_rendering_driver, int p_width, int p_height) { + rendering_driver = p_rendering_driver; + width = p_width; + height = p_height; +} +#endif diff --git a/servers/rendering/rendering_native_surface_external_target.h b/servers/rendering/rendering_native_surface_external_target.h new file mode 100644 index 000000000000..b3e05462e1ed --- /dev/null +++ b/servers/rendering/rendering_native_surface_external_target.h @@ -0,0 +1,114 @@ +/**************************************************************************/ +/* rendering_native_surface_external_target.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. */ +/**************************************************************************/ + +#pragma once + +#include "servers/rendering/rendering_native_surface.h" + +#include "core/variant/native_ptr.h" +#include "drivers/gles3/rasterizer_gles3.h" +#include "drivers/vulkan/rendering_context_driver_vulkan.h" +#include "servers/display_server.h" +#include "servers/rendering/gl_manager.h" + +#ifdef EXTERNAL_TARGET_ENABLED + +class GLManagerExternal; + +class RenderingNativeSurfaceExternalTarget : public RenderingNativeSurface { // Defines both Vulkan and OpenGL behavior. + GDCLASS(RenderingNativeSurfaceExternalTarget, RenderingNativeSurface); + + static void _bind_methods(); + +private: + // Common members: + String rendering_driver; + + uint32_t width = 0; + uint32_t height = 0; + + // Vulkan specific members: + Callable post_images_created_callback; + Callable pre_images_released_callback; + RenderingContextDriver::SurfaceID surface; + +#ifdef GLES3_ENABLED + // OpenGL specific members: + Callable make_current; + Callable done_current; + uint64_t get_proc_address = 0u; +#endif + +public: + // VULKAN SPECIFIC OPERATIONS: + uint32_t get_width() const; + uint32_t get_height() const; + DisplayServer::WindowID get_window(); + void set_surface(RenderingContextDriver::SurfaceID p_surface); + RenderingContextDriver::SurfaceID get_surface_id(); + + static Ref create_api(String p_rendering_driver, Size2i p_initial_size); + +#ifdef VULKAN_ENABLED + static Ref create(String p_rendering_driver, Size2i p_initial_size); +#endif + + virtual RenderingContextDriver *create_rendering_context(const String &p_driver_name) override final; + + virtual void setup_external_swapchain_callbacks() override final; + + // Called by host (registered in GDExtension): + + void set_external_swapchain_callbacks(Callable p_images_created, Callable p_images_released); + + void resize(Size2i p_new_size); + + // Call in Qt to get the next image that is already ready by Godot + // Wrap it in QSGTexture and set it as render target + int acquire_next_image(); + + // When the rendering is done for an image, call this in Qt to release it, so Godot knows that it can use it as a render target again. + void release_image(int p_index); + + // OPENGL SPECIFIC OPERATIONS: +#ifdef GLES3_ENABLED + void set_opengl_callbacks(Callable p_make_current, Callable p_done_current, uint64_t p_get_proc_address); +#endif + virtual GLManager *create_gl_manager(const String &p_driver_name) override; + uint32_t get_frame_texture(DisplayServer::WindowID p_window_id) const; + + virtual void *get_native_id() const override { return nullptr; } + + RenderingNativeSurfaceExternalTarget() {} + RenderingNativeSurfaceExternalTarget(String p_rendering_driver, int p_width, int p_height); + ~RenderingNativeSurfaceExternalTarget() {} +}; + +#endif diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp index 6d9d647a418d..036e470a264f 100644 --- a/servers/rendering/rendering_server_default.cpp +++ b/servers/rendering/rendering_server_default.cpp @@ -242,11 +242,31 @@ void RenderingServerDefault::_finish() { RSG::canvas->finalize(); memdelete(RSG::canvas); + RSG::canvas = nullptr; + RSG::rasterizer->finalize(); memdelete(RSG::viewport); + RSG::viewport = nullptr; + memdelete(RSG::rasterizer); + RSG::rasterizer = nullptr; memdelete(RSG::scene); + RSG::scene = nullptr; + memdelete(RSG::camera_attributes); + RSG::camera_attributes = nullptr; + + RSG::threaded = false; + + RSG::utilities = nullptr; + RSG::light_storage = nullptr; + RSG::material_storage = nullptr; + RSG::mesh_storage = nullptr; + RSG::particles_storage = nullptr; + RSG::texture_storage = nullptr; + RSG::gi = nullptr; + RSG::fog = nullptr; + RSG::canvas_render = nullptr; } void RenderingServerDefault::init() { diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index 3c198652b23b..3a01c19f5f1c 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -1104,7 +1104,7 @@ class RenderingServerDefault : public RenderingServer { #define ServerName RendererCompositor #define server_name RSG::rasterizer - FUNC4S(set_boot_image, const Ref &, const Color &, bool, bool) + FUNC5S(set_boot_image, const Ref &, const Color &, bool, DisplayServer::WindowID, bool) /* STATUS INFORMATION */ diff --git a/servers/rendering/shader_compiler.cpp b/servers/rendering/shader_compiler.cpp index c23ba8ee010d..d9bbeffade5d 100644 --- a/servers/rendering/shader_compiler.cpp +++ b/servers/rendering/shader_compiler.cpp @@ -41,6 +41,9 @@ static String _mktab(int p_level) { static String _typestr(SL::DataType p_type) { String type = ShaderLanguage::get_datatype_name(p_type); + if (p_type == ShaderLanguage::TYPE_SAMPLERCUBEARRAY) { + type += "Fix"; + } if (!RS::get_singleton()->is_low_end() && ShaderLanguage::is_sampler_type(p_type)) { type = type.replace("sampler", "texture"); //we use textures instead of samplers in Vulkan GLSL } @@ -300,6 +303,10 @@ String ShaderCompiler::_get_sampler_name(ShaderLanguage::TextureFilter p_filter, return String(name_mapping[p_filter + (p_repeat == ShaderLanguage::REPEAT_ENABLE ? ShaderLanguage::FILTER_DEFAULT : 0)]); } +bool ShaderCompiler::_is_cube_map_array_function(const String &p_function_name) { + return p_function_name == "textureSize" || p_function_name == "texture" || p_function_name == "texture" || p_function_name == "textureLod" || p_function_name == "textureGrad"; +} + void ShaderCompiler::_dump_function_deps(const SL::ShaderNode *p_node, const StringName &p_for_func, const HashMap &p_func_code, String &r_to_add, HashSet &added) { int fidx = -1; @@ -1170,6 +1177,7 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene bool is_screen_texture = false; bool texture_func_no_uv = false; bool texture_func_returns_data = false; + bool cube_map_array_fix = false; if (onode->op == SL::OP_STRUCT) { code += _mkid(vnode->name); @@ -1183,6 +1191,10 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene if (is_internal_func) { code += vnode->name; + if (_is_cube_map_array_function(vnode->name) && onode->arguments.size() > 1 && onode->arguments[1]->get_datatype() == SL::TYPE_SAMPLERCUBEARRAY) { + cube_map_array_fix = true; + code += "Fix"; + } is_texture_func = texture_functions.has(vnode->name); texture_func_no_uv = (vnode->name == "textureSize" || vnode->name == "textureQueryLevels"); texture_func_returns_data = texture_func_no_uv || vnode->name == "textureQueryLod"; @@ -1322,7 +1334,11 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene data_type_name = ShaderLanguage::get_datatype_name(onode->arguments[i]->get_datatype()); } - code += data_type_name + "(" + node_code + ", " + sampler_name + ")"; + if (cube_map_array_fix) { + code += node_code + ", " + sampler_name; + } else { + code += data_type_name + "(" + node_code + ", " + sampler_name + ")"; + } } else if (actions.check_multiview_samplers && correct_texture_uniform && RS::get_singleton()->is_low_end()) { // Texture function on low end hardware (i.e. OpenGL). // We just need to know if the texture supports multiview. diff --git a/servers/rendering/shader_compiler.h b/servers/rendering/shader_compiler.h index 16c1a034bfe5..e58e2aa86fbf 100644 --- a/servers/rendering/shader_compiler.h +++ b/servers/rendering/shader_compiler.h @@ -109,6 +109,8 @@ class ShaderCompiler { String _get_sampler_name(ShaderLanguage::TextureFilter p_filter, ShaderLanguage::TextureRepeat p_repeat); + bool _is_cube_map_array_function(const String &p_function_name); + void _dump_function_deps(const ShaderLanguage::ShaderNode *p_node, const StringName &p_for_func, const HashMap &p_func_code, String &r_to_add, HashSet &added); String _dump_node_code(const ShaderLanguage::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning, bool p_scope = true); diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index 7e8764567837..e66357eb8e9a 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -3154,7 +3154,7 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "textureSize", TYPE_IVEC3, { TYPE_ISAMPLER3D, TYPE_INT, TYPE_VOID }, { "sampler", "lod" }, TAG_GLOBAL, false }, { "textureSize", TYPE_IVEC3, { TYPE_USAMPLER3D, TYPE_INT, TYPE_VOID }, { "sampler", "lod" }, TAG_GLOBAL, false }, { "textureSize", TYPE_IVEC2, { TYPE_SAMPLERCUBE, TYPE_INT, TYPE_VOID }, { "sampler", "lod" }, TAG_GLOBAL, false }, - { "textureSize", TYPE_IVEC2, { TYPE_SAMPLERCUBEARRAY, TYPE_INT, TYPE_VOID }, { "sampler", "lod" }, TAG_GLOBAL, false }, + { "textureSize", TYPE_IVEC3, { TYPE_SAMPLERCUBEARRAY, TYPE_INT, TYPE_VOID }, { "sampler", "lod" }, TAG_GLOBAL, false }, // texture diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp index bca38384808b..5aa4c8193086 100644 --- a/servers/rendering/shader_types.cpp +++ b/servers/rendering/shader_types.cpp @@ -526,3 +526,8 @@ ShaderTypes::ShaderTypes() { shader_types.insert(type); } } + +ShaderTypes::~ShaderTypes() { + ERR_FAIL_COND(singleton != this); + singleton = nullptr; +} diff --git a/servers/rendering/shader_types.h b/servers/rendering/shader_types.h index cf42549d0145..03eee7e69a95 100644 --- a/servers/rendering/shader_types.h +++ b/servers/rendering/shader_types.h @@ -57,4 +57,5 @@ class ShaderTypes { const List &get_types_list() const; ShaderTypes(); + ~ShaderTypes(); }; diff --git a/servers/rendering/storage/texture_storage.h b/servers/rendering/storage/texture_storage.h index 135bcc39fc50..280925090813 100644 --- a/servers/rendering/storage/texture_storage.h +++ b/servers/rendering/storage/texture_storage.h @@ -147,7 +147,7 @@ class RendererTextureStorage { virtual Size2i render_target_get_size(RID p_render_target) const = 0; virtual void render_target_set_transparent(RID p_render_target, bool p_is_transparent) = 0; virtual bool render_target_get_transparent(RID p_render_target) const = 0; - virtual void render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) = 0; + virtual void render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen, DisplayServer::WindowID p_direct_to_screen_id) = 0; virtual bool render_target_get_direct_to_screen(RID p_render_target) const = 0; virtual bool render_target_was_used(RID p_render_target) const = 0; virtual void render_target_set_as_unused(RID p_render_target) = 0; diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 8202dff8cbe2..79770794e005 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -3489,7 +3489,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_test_texture"), &RenderingServer::get_test_texture); ClassDB::bind_method(D_METHOD("get_white_texture"), &RenderingServer::get_white_texture); - ClassDB::bind_method(D_METHOD("set_boot_image", "image", "color", "scale", "use_filter"), &RenderingServer::set_boot_image, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("set_boot_image", "image", "color", "scale", "screen", "use_filter"), &RenderingServer::set_boot_image, DEFVAL(true)); 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); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index a5a62b9653f4..700f26a5840c 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -1836,7 +1836,7 @@ class RenderingServer : public Object { virtual void mesh_add_surface_from_mesh_data(RID p_mesh, const Geometry3D::MeshData &p_mesh_data); virtual void mesh_add_surface_from_planes(RID p_mesh, const Vector &p_planes); - virtual void set_boot_image(const Ref &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true) = 0; + virtual void set_boot_image(const Ref &p_image, const Color &p_color, bool p_scale, DisplayServer::WindowID p_screen = DisplayServer::MAIN_WINDOW_ID, bool p_use_filter = true) = 0; virtual Color get_default_clear_color() = 0; virtual void set_default_clear_color(const Color &p_color) = 0; diff --git a/thirdparty/pcre2/src/pcre2_chkdint.c b/thirdparty/pcre2/src/pcre2_chkdint.c index 70830236999d..712b9514cb05 100644 --- a/thirdparty/pcre2/src/pcre2_chkdint.c +++ b/thirdparty/pcre2/src/pcre2_chkdint.c @@ -63,7 +63,7 @@ The INT64_OR_DOUBLE type is a 64-bit integer type when available, otherwise double. */ BOOL -PRIV(ckd_smul)(PCRE2_SIZE *r, int a, int b) +PCRE2_SUFFIX(_pcre2_ckd_smul)(PCRE2_SIZE *r, int a, int b) { #ifdef HAVE_BUILTIN_MUL_OVERFLOW PCRE2_SIZE m; diff --git a/thirdparty/pcre2/src/pcre2_compile.c b/thirdparty/pcre2/src/pcre2_compile.c index 0ffac8939cb6..909717bf356d 100644 --- a/thirdparty/pcre2/src/pcre2_compile.c +++ b/thirdparty/pcre2/src/pcre2_compile.c @@ -7288,7 +7288,7 @@ for (;; pptr++) if (lengthptr != NULL) { PCRE2_SIZE delta; - if (PRIV(ckd_smul)(&delta, replicate, 1 + LINK_SIZE) || + if (PCRE2_SUFFIX(_pcre2_ckd_smul)(&delta, replicate, 1 + LINK_SIZE) || OFLOW_MAX - *lengthptr < delta) { *errorcodeptr = ERR20; @@ -7456,7 +7456,7 @@ for (;; pptr++) if (lengthptr != NULL) { PCRE2_SIZE delta; - if (PRIV(ckd_smul)(&delta, repeat_min - 1, + if (PCRE2_SUFFIX(_pcre2_ckd_smul)(&delta, repeat_min - 1, (int)length_prevgroup) || OFLOW_MAX - *lengthptr < delta) { @@ -7506,7 +7506,7 @@ for (;; pptr++) if (lengthptr != NULL && repeat_max > 0) { PCRE2_SIZE delta; - if (PRIV(ckd_smul)(&delta, repeat_max, + if (PCRE2_SUFFIX(_pcre2_ckd_smul)(&delta, repeat_max, (int)length_prevgroup + 1 + 2 + 2*LINK_SIZE) || OFLOW_MAX + (2 + 2*LINK_SIZE) - *lengthptr < delta) { diff --git a/thirdparty/pcre2/src/pcre2_internal.h b/thirdparty/pcre2/src/pcre2_internal.h index 6e0a5e05d03f..c4439d4a9ceb 100644 --- a/thirdparty/pcre2/src/pcre2_internal.h +++ b/thirdparty/pcre2/src/pcre2_internal.h @@ -2226,7 +2226,7 @@ extern void * _pcre2_memmove(void *, const void *, size_t); #endif /* PCRE2_CODE_UNIT_WIDTH */ -extern BOOL PRIV(ckd_smul)(PCRE2_SIZE *, int, int); +extern BOOL PCRE2_SUFFIX(_pcre2_ckd_smul)(PCRE2_SIZE *, int, int); #include "pcre2_util.h"