diff --git a/addons/libLibRetroHost-d.so b/addons/libLibRetroHost-d.so index 65858b7..e75170c 100755 Binary files a/addons/libLibRetroHost-d.so and b/addons/libLibRetroHost-d.so differ diff --git a/gdlibretro/CMakeFiles/LibRetroHost.dir/src/RegisterExtension.cpp.o b/gdlibretro/CMakeFiles/LibRetroHost.dir/src/RegisterExtension.cpp.o index d9eed2a..b94f8e0 100644 Binary files a/gdlibretro/CMakeFiles/LibRetroHost.dir/src/RegisterExtension.cpp.o and b/gdlibretro/CMakeFiles/LibRetroHost.dir/src/RegisterExtension.cpp.o differ diff --git a/gdlibretro/CMakeFiles/LibRetroHost.dir/src/RetroHost.cpp.o b/gdlibretro/CMakeFiles/LibRetroHost.dir/src/RetroHost.cpp.o index 757088e..61d5e23 100644 Binary files a/gdlibretro/CMakeFiles/LibRetroHost.dir/src/RetroHost.cpp.o and b/gdlibretro/CMakeFiles/LibRetroHost.dir/src/RetroHost.cpp.o differ diff --git a/gdlibretro/src/RegisterExtension.cpp b/gdlibretro/src/RegisterExtension.cpp index 3fdb8be..41e2483 100644 --- a/gdlibretro/src/RegisterExtension.cpp +++ b/gdlibretro/src/RegisterExtension.cpp @@ -8,50 +8,70 @@ #include "RetroHost.hpp" +// Singleton instance pointer static RetroHost *retro_host_singleton = nullptr; namespace { + + // Initialize the extension and register the singleton void initialize_extension(godot::ModuleInitializationLevel p_level) { if (p_level != godot::MODULE_INITIALIZATION_LEVEL_SCENE) { return; } - godot::ClassDB::register_class(); - godot::UtilityFunctions::print("[RetroHost] Initializing extension..."); + + // Register the RetroHost class + godot::ClassDB::register_class(); + godot::UtilityFunctions::print("[RetroHost] RetroHost class registered."); + + // Create the singleton instance retro_host_singleton = memnew(RetroHost()); if (!retro_host_singleton) { godot::UtilityFunctions::printerr("[RetroHost] Failed to allocate memory for singleton."); - return; + } else { + godot::UtilityFunctions::print("[RetroHost] Singleton created successfully."); } + + // Register the singleton with the engine godot::Engine::get_singleton()->register_singleton("RetroHost", RetroHost::get_singleton()); godot::UtilityFunctions::print("[RetroHost] Singleton registered successfully."); - } + // Uninitialize the extension and unregister the singleton void uninitialize_extension(godot::ModuleInitializationLevel p_level) { if (p_level != godot::MODULE_INITIALIZATION_LEVEL_SCENE) { return; } - godot::Engine::get_singleton()->unregister_singleton("RetroHost"); - memdelete(retro_host_singleton); + + godot::UtilityFunctions::print("[RetroHost] Uninitializing extension..."); + + // Unregister and delete the singleton instance + if (retro_host_singleton) { + godot::Engine::get_singleton()->unregister_singleton("RetroHost"); + memdelete(retro_host_singleton); + retro_host_singleton = nullptr; + godot::UtilityFunctions::print("[RetroHost] Singleton unregistered and memory released."); + } else { + godot::UtilityFunctions::printerr("[RetroHost] Singleton instance was null during uninitialization."); + } } } +// Entry point for the GDExtension system extern "C" { GDExtensionBool GDE_EXPORT GDExtensionInit( GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) { - //godot::UtilityFunctions::print("[LibRetroHost] GDExtensionInit called"); - + godot::GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization); + // Register the initializer and terminator functions init_obj.register_initializer(initialize_extension); init_obj.register_terminator(uninitialize_extension); init_obj.set_minimum_library_initialization_level(godot::MODULE_INITIALIZATION_LEVEL_SCENE); - //godot::UtilityFunctions::print("[LibRetroHost] Initialization setup completed."); return init_obj.init(); } } diff --git a/gdlibretro/src/RetroHost.cpp b/gdlibretro/src/RetroHost.cpp index 5874c88..370b068 100644 --- a/gdlibretro/src/RetroHost.cpp +++ b/gdlibretro/src/RetroHost.cpp @@ -47,15 +47,23 @@ std::string GetLastErrorAsStr() RetroHost::RetroHost() { - godot::UtilityFunctions::print("[RetroHost] Constructor"); + godot::UtilityFunctions::print("[RetroHost] Constructor called. Initializing singleton."); singleton = this; this->vfs.init_vfs_interface(); + + // Initialize core variables + this->core.handle = nullptr; + this->core.initialized = false; + this->frame_buffer.unref(); // Reset the Ref properly + godot::UtilityFunctions::print("[RetroHost] Initialization complete."); } RetroHost::~RetroHost() { - godot::UtilityFunctions::print("[RetroHost] Destructor"); + godot::UtilityFunctions::print("[RetroHost] Destructor called. Cleaning up resources."); this->unload_core(); + singleton = nullptr; + godot::UtilityFunctions::print("[RetroHost] Resources cleaned up and singleton destroyed."); } RetroHost *RetroHost::singleton = nullptr; @@ -77,15 +85,15 @@ RetroHost *RetroHost::get_singleton() } \ } while (0) -bool RetroHost::load_core(godot::String name) { +bool RetroHost::load_core(godot::String name) +{ this->unload_core(); godot::UtilityFunctions::print("[RetroHost] Starting load_core with name: ", name); godot::String lib_path; if (godot::OS::get_singleton()->has_feature("editor")) { - this->cwd = - godot::ProjectSettings::get_singleton()->globalize_path("res://") + "libretro-cores/"; - lib_path = cwd + name + ".dll"; // Editor path (Windows assumed default) + this->cwd = godot::ProjectSettings::get_singleton()->globalize_path("res://") + "libretro-cores/"; + lib_path = cwd + name; godot::UtilityFunctions::print("[RetroHost] Editor mode detected. Core path: ", lib_path); } else { this->cwd = godot::OS::get_singleton()->get_executable_path().get_base_dir(); @@ -96,14 +104,13 @@ bool RetroHost::load_core(godot::String name) { #ifdef PLATFORM_WINDOWS this->core.handle = LoadLibrary(lib_path.utf8().get_data()); if (this->core.handle == NULL) { - godot::UtilityFunctions::printerr("[RetroHost] Failed to load core \"", lib_path, "\". Error: ", GetLastErrorAsStr().c_str()); + godot::UtilityFunctions::printerr("[RetroHost] Failed to load core \"", lib_path, "\". Error: ", GetLastErrorAsStr().c_str()); return false; } #elif defined(PLATFORM_LINUX) || defined(PLATFORM_ANDROID) this->core.handle = dlopen(lib_path.utf8().get_data(), RTLD_LAZY); if (this->core.handle == nullptr) { - godot::UtilityFunctions::printerr("[RetroHost] dlopen failed: ", dlerror()); - godot::UtilityFunctions::printerr("[RetroHost] Failed to load core \"", lib_path, "\". Error: ", GetLastErrorAsStr().c_str()); + godot::UtilityFunctions::printerr("[RetroHost] Failed to load core \"", lib_path, "\". Error: ", dlerror()); return false; } #endif @@ -131,46 +138,25 @@ bool RetroHost::load_core(godot::String name) { this->core.retro_init(); godot::UtilityFunctions::print("[RetroHost] Core initialized successfully."); - godot::UtilityFunctions::print("[RetroHost] Attempting to load game..."); - if (!this->core.retro_load_game(nullptr)) { - godot::UtilityFunctions::printerr("[RetroHost] Failed to load game."); - return false; - } - godot::UtilityFunctions::print("[RetroHost] Game loaded successfully."); - - struct retro_system_av_info av; - this->core.retro_get_system_av_info(&av); - godot::UtilityFunctions::print("[RetroHost] Retrieved system AV info."); - - this->core_video_init(&av.geometry); - godot::UtilityFunctions::print("[RetroHost] Video initialized."); - - this->core_audio_init(av); - godot::UtilityFunctions::print("[RetroHost] Audio initialized."); - this->core.initialized = true; - godot::UtilityFunctions::print("[RetroHost] Core fully initialized and ready."); return true; } void RetroHost::unload_core() { - if (this->core.initialized) - { + if (this->core.initialized) { godot::UtilityFunctions::print("[RetroHost] Deinitializing core..."); this->core.retro_deinit(); this->core.initialized = false; } #ifdef PLATFORM_WINDOWS - if (this->core.handle != NULL) - { + if (this->core.handle != NULL) { FreeLibrary(this->core.handle); this->core.handle = NULL; } #elif defined(PLATFORM_LINUX) || defined(PLATFORM_ANDROID) - if (this->core.handle != nullptr) - { + if (this->core.handle != nullptr) { dlclose(this->core.handle); this->core.handle = nullptr; } @@ -178,17 +164,14 @@ void RetroHost::unload_core() godot::UtilityFunctions::print("[RetroHost] Core unloaded successfully."); } -void RetroHost::run(){ - - godot::UtilityFunctions::print("[RetroHost] Starting core run..."); - - if (!this->core.initialized) - { +void RetroHost::run() +{ + if (!this->core.initialized) { godot::UtilityFunctions::printerr("[RetroHost] Cannot run. Core not initialized."); return; } + godot::UtilityFunctions::print("[RetroHost] Running core..."); this->core.retro_run(); - godot::UtilityFunctions::print("[RetroHost] Core ran successfully."); } void RetroHost::_bind_methods() @@ -196,4 +179,4 @@ void RetroHost::_bind_methods() godot::ClassDB::bind_method(godot::D_METHOD("load_core", "name"), &RetroHost::load_core); godot::ClassDB::bind_method(godot::D_METHOD("unload_core"), &RetroHost::unload_core); godot::ClassDB::bind_method(godot::D_METHOD("run"), &RetroHost::run); -} +} \ No newline at end of file diff --git a/main.gd b/main.gd index a73ea28..1e83338 100644 --- a/main.gd +++ b/main.gd @@ -23,10 +23,10 @@ func _ready(): var success = await loader.start_emulation(core_path, rom_path) # Use await to call the coroutine if success: - print("[main] Game started successfully.") + print("[main] Game started successfully") start_emulation_loop() else: - print("[main] Failed to start the game.") + print("[main] Failed to start the game") func start_emulation_loop(): """ diff --git a/prompt.sh b/prompt.sh index 301ccb8..30cd85e 100755 --- a/prompt.sh +++ b/prompt.sh @@ -33,16 +33,23 @@ done write "" write "My issue now is the following, can you help me to fix it?" write ' -When I load godot I get this crash: +My issue is that I am not able to start the emulated game, I am getting the following error: - godot . +Godot Engine v4.3.stable.flathub.77dcf97d8 - https://godotengine.org +OpenGL API 4.6 (Core Profile) Mesa 24.2.7 (git-3900828265) - Compatibility - Using Device: Intel - Mesa Intel(R) Graphics (ADL GT2) -================================================================ -handle_crash: Program crashed with signal 11 -Engine version: Godot Engine v4.2.2.rc2.mono.official (c61a68614e5b030a4a1e11abaa5a893b8017f78d) -Dumping the backtrace. Please include this when reporting the bug to the project developer. -[1] /lib/x86_64-linux-gnu/libc.so.6(+0x45250) [0x7ea94c445250] (??:0) --- END OF BACKTRACE -- -================================================================ -Annullato (core dump creato) +[RetroHost] Initializing extension... +[RetroHost] RetroHost class registered. +[RetroHost] Constructor called. Initializing singleton. +[RetroHost] Initialization complete. +[RetroHost] Singleton registered successfully. +[main] Entering _ready function +[main] File res://cores/genesis_plus_gx_libretro.so exists +[main] File res://roms/megadrive/Sonic the Hedgehog.bin exists +[main] Core path: res://cores/genesis_plus_gx_libretro.so +[main] ROM path: res://roms/megadrive/Sonic the Hedgehog.bin +[libretro_loader] Starting emulation with core: res://cores/genesis_plus_gx_libretro.so, ROM: res://roms/megadrive/Sonic the Hedgehog.bin +[libretro_loader] RetroHost status: +[libretro_loader] RetroHost singleton not found! +[main] Failed to start the game ' \ No newline at end of file diff --git a/scripts/libretro_loader.gd b/scripts/libretro_loader.gd index 3c7e3d2..fb13aa3 100644 --- a/scripts/libretro_loader.gd +++ b/scripts/libretro_loader.gd @@ -10,17 +10,26 @@ var current_rom : String = "" # Initialize to an empty string func start_emulation(core_path: String, rom_path: String) -> bool: print("[libretro_loader] Starting emulation with core: ", core_path, ", ROM: ", rom_path) + # Debug RetroHost access + print("[libretro_loader] RetroHost status: ", retro_host) + # Check if RetroHost is available if not retro_host: - push_error("[libretro_loader] RetroHost singleton not found!") + var message = "[libretro_loader] RetroHost singleton not found!" + push_error(message) + print(message) return false if not core_path: - push_error("[libretro_loader] Core path is missing.") + var message = "[libretro_loader] Core path is missing." + push_error(message) + print(message) return false - + if not rom_path: - push_error("[libretro_loader] ROM path is missing.") + var message = "[libretro_loader] ROM path is missing." + push_error(message) + print(message) return false # Load the core (via RetroHost) @@ -100,26 +109,37 @@ func _process(delta): func _ready(): """ - Initializes the SubViewport and TextureRect. + Initializes the SubViewport and TextureRect and waits for RetroHost singleton. """ print("[libretro_loader] _ready: Initializing SubViewport and TextureRect.") if sub_viewport and texture_rect: print("[libretro_loader] SubViewport and TextureRect initialized successfully.") else: - push_error("Error: SubViewport or TextureRect is missing.") + push_error("[libretro_loader] Error: SubViewport or TextureRect is missing.") return - if not retro_host: - push_error("[libretro_loader] RetroHost singleton not found! Emulation cannot proceed.") - return - print("[libretro_loader] RetroHost singleton initialized successfully.") - # Ensure SubViewport always renders sub_viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS print("[libretro_loader] SubViewport set to always update.") - # Use await to call the coroutine - var success = await start_emulation("res://cores/genesis_plus_gx_libretro.so", "res://roms/megadrive/Sonic") + print("[libretro_loader] _ready: Waiting for RetroHost singleton...") + + while not Engine.get_singleton("RetroHost"): + print("[libretro_loader] Waiting for RetroHost...") + await get_tree().idle_frame + + print("[libretro_loader] _ready: Wait ended") + + # Assign the RetroHost singleton after it's available + retro_host = Engine.get_singleton("RetroHost") + if retro_host: + print("[libretro_loader] RetroHost singleton initialized successfully.") + else: + push_error("[libretro_loader] Failed to find RetroHost singleton!") + return + + # Proceed with starting emulation + var success = await start_emulation("res://cores/genesis_plus_gx_libretro.so", "res://roms/megadrive/Sonic the Hedgehog.bin") if success: print("[libretro_loader] Emulation started successfully.") else: