Checkpoint - Issue: singleton cannot be loaded

This commit is contained in:
XargonWan 2024-12-27 13:52:03 +09:00
parent 70432207db
commit d8ce8263b9
8 changed files with 105 additions and 75 deletions

Binary file not shown.

View file

@ -8,50 +8,70 @@
#include "RetroHost.hpp" #include "RetroHost.hpp"
// Singleton instance pointer
static RetroHost *retro_host_singleton = nullptr; static RetroHost *retro_host_singleton = nullptr;
namespace { namespace {
// Initialize the extension and register the singleton
void initialize_extension(godot::ModuleInitializationLevel p_level) { void initialize_extension(godot::ModuleInitializationLevel p_level) {
if (p_level != godot::MODULE_INITIALIZATION_LEVEL_SCENE) { if (p_level != godot::MODULE_INITIALIZATION_LEVEL_SCENE) {
return; return;
} }
godot::ClassDB::register_class<RetroHost>();
godot::UtilityFunctions::print("[RetroHost] Initializing extension..."); godot::UtilityFunctions::print("[RetroHost] Initializing extension...");
// Register the RetroHost class
godot::ClassDB::register_class<RetroHost>();
godot::UtilityFunctions::print("[RetroHost] RetroHost class registered.");
// Create the singleton instance
retro_host_singleton = memnew(RetroHost()); retro_host_singleton = memnew(RetroHost());
if (!retro_host_singleton) { if (!retro_host_singleton) {
godot::UtilityFunctions::printerr("[RetroHost] Failed to allocate memory for 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::Engine::get_singleton()->register_singleton("RetroHost", RetroHost::get_singleton());
godot::UtilityFunctions::print("[RetroHost] Singleton registered successfully."); godot::UtilityFunctions::print("[RetroHost] Singleton registered successfully.");
} }
// Uninitialize the extension and unregister the singleton
void uninitialize_extension(godot::ModuleInitializationLevel p_level) { void uninitialize_extension(godot::ModuleInitializationLevel p_level) {
if (p_level != godot::MODULE_INITIALIZATION_LEVEL_SCENE) { if (p_level != godot::MODULE_INITIALIZATION_LEVEL_SCENE) {
return; return;
} }
godot::UtilityFunctions::print("[RetroHost] Uninitializing extension...");
// Unregister and delete the singleton instance
if (retro_host_singleton) {
godot::Engine::get_singleton()->unregister_singleton("RetroHost"); godot::Engine::get_singleton()->unregister_singleton("RetroHost");
memdelete(retro_host_singleton); 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" { extern "C" {
GDExtensionBool GDE_EXPORT GDExtensionInit( GDExtensionBool GDE_EXPORT GDExtensionInit(
GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionInterfaceGetProcAddress p_get_proc_address,
GDExtensionClassLibraryPtr p_library, GDExtensionClassLibraryPtr p_library,
GDExtensionInitialization *r_initialization) { GDExtensionInitialization *r_initialization) {
//godot::UtilityFunctions::print("[LibRetroHost] GDExtensionInit called");
godot::GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization); 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_initializer(initialize_extension);
init_obj.register_terminator(uninitialize_extension); init_obj.register_terminator(uninitialize_extension);
init_obj.set_minimum_library_initialization_level(godot::MODULE_INITIALIZATION_LEVEL_SCENE); init_obj.set_minimum_library_initialization_level(godot::MODULE_INITIALIZATION_LEVEL_SCENE);
//godot::UtilityFunctions::print("[LibRetroHost] Initialization setup completed.");
return init_obj.init(); return init_obj.init();
} }
} }

View file

@ -47,15 +47,23 @@ std::string GetLastErrorAsStr()
RetroHost::RetroHost() RetroHost::RetroHost()
{ {
godot::UtilityFunctions::print("[RetroHost] Constructor"); godot::UtilityFunctions::print("[RetroHost] Constructor called. Initializing singleton.");
singleton = this; singleton = this;
this->vfs.init_vfs_interface(); this->vfs.init_vfs_interface();
// Initialize core variables
this->core.handle = nullptr;
this->core.initialized = false;
this->frame_buffer.unref(); // Reset the Ref<godot::Image> properly
godot::UtilityFunctions::print("[RetroHost] Initialization complete.");
} }
RetroHost::~RetroHost() RetroHost::~RetroHost()
{ {
godot::UtilityFunctions::print("[RetroHost] Destructor"); godot::UtilityFunctions::print("[RetroHost] Destructor called. Cleaning up resources.");
this->unload_core(); this->unload_core();
singleton = nullptr;
godot::UtilityFunctions::print("[RetroHost] Resources cleaned up and singleton destroyed.");
} }
RetroHost *RetroHost::singleton = nullptr; RetroHost *RetroHost::singleton = nullptr;
@ -77,15 +85,15 @@ RetroHost *RetroHost::get_singleton()
} \ } \
} while (0) } while (0)
bool RetroHost::load_core(godot::String name) { bool RetroHost::load_core(godot::String name)
{
this->unload_core(); this->unload_core();
godot::UtilityFunctions::print("[RetroHost] Starting load_core with name: ", name); godot::UtilityFunctions::print("[RetroHost] Starting load_core with name: ", name);
godot::String lib_path; godot::String lib_path;
if (godot::OS::get_singleton()->has_feature("editor")) { if (godot::OS::get_singleton()->has_feature("editor")) {
this->cwd = this->cwd = godot::ProjectSettings::get_singleton()->globalize_path("res://") + "libretro-cores/";
godot::ProjectSettings::get_singleton()->globalize_path("res://") + "libretro-cores/"; lib_path = cwd + name;
lib_path = cwd + name + ".dll"; // Editor path (Windows assumed default)
godot::UtilityFunctions::print("[RetroHost] Editor mode detected. Core path: ", lib_path); godot::UtilityFunctions::print("[RetroHost] Editor mode detected. Core path: ", lib_path);
} else { } else {
this->cwd = godot::OS::get_singleton()->get_executable_path().get_base_dir(); this->cwd = godot::OS::get_singleton()->get_executable_path().get_base_dir();
@ -102,8 +110,7 @@ bool RetroHost::load_core(godot::String name) {
#elif defined(PLATFORM_LINUX) || defined(PLATFORM_ANDROID) #elif defined(PLATFORM_LINUX) || defined(PLATFORM_ANDROID)
this->core.handle = dlopen(lib_path.utf8().get_data(), RTLD_LAZY); this->core.handle = dlopen(lib_path.utf8().get_data(), RTLD_LAZY);
if (this->core.handle == nullptr) { if (this->core.handle == nullptr) {
godot::UtilityFunctions::printerr("[RetroHost] dlopen failed: ", dlerror()); godot::UtilityFunctions::printerr("[RetroHost] Failed to load core \"", lib_path, "\". Error: ", dlerror());
godot::UtilityFunctions::printerr("[RetroHost] Failed to load core \"", lib_path, "\". Error: ", GetLastErrorAsStr().c_str());
return false; return false;
} }
#endif #endif
@ -131,46 +138,25 @@ bool RetroHost::load_core(godot::String name) {
this->core.retro_init(); this->core.retro_init();
godot::UtilityFunctions::print("[RetroHost] Core initialized successfully."); 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; this->core.initialized = true;
godot::UtilityFunctions::print("[RetroHost] Core fully initialized and ready.");
return true; return true;
} }
void RetroHost::unload_core() void RetroHost::unload_core()
{ {
if (this->core.initialized) if (this->core.initialized) {
{
godot::UtilityFunctions::print("[RetroHost] Deinitializing core..."); godot::UtilityFunctions::print("[RetroHost] Deinitializing core...");
this->core.retro_deinit(); this->core.retro_deinit();
this->core.initialized = false; this->core.initialized = false;
} }
#ifdef PLATFORM_WINDOWS #ifdef PLATFORM_WINDOWS
if (this->core.handle != NULL) if (this->core.handle != NULL) {
{
FreeLibrary(this->core.handle); FreeLibrary(this->core.handle);
this->core.handle = NULL; this->core.handle = NULL;
} }
#elif defined(PLATFORM_LINUX) || defined(PLATFORM_ANDROID) #elif defined(PLATFORM_LINUX) || defined(PLATFORM_ANDROID)
if (this->core.handle != nullptr) if (this->core.handle != nullptr) {
{
dlclose(this->core.handle); dlclose(this->core.handle);
this->core.handle = nullptr; this->core.handle = nullptr;
} }
@ -178,17 +164,14 @@ void RetroHost::unload_core()
godot::UtilityFunctions::print("[RetroHost] Core unloaded successfully."); godot::UtilityFunctions::print("[RetroHost] Core unloaded successfully.");
} }
void RetroHost::run(){ void RetroHost::run()
{
godot::UtilityFunctions::print("[RetroHost] Starting core run..."); if (!this->core.initialized) {
if (!this->core.initialized)
{
godot::UtilityFunctions::printerr("[RetroHost] Cannot run. Core not initialized."); godot::UtilityFunctions::printerr("[RetroHost] Cannot run. Core not initialized.");
return; return;
} }
godot::UtilityFunctions::print("[RetroHost] Running core...");
this->core.retro_run(); this->core.retro_run();
godot::UtilityFunctions::print("[RetroHost] Core ran successfully.");
} }
void RetroHost::_bind_methods() void RetroHost::_bind_methods()

View file

@ -23,10 +23,10 @@ func _ready():
var success = await loader.start_emulation(core_path, rom_path) # Use await to call the coroutine var success = await loader.start_emulation(core_path, rom_path) # Use await to call the coroutine
if success: if success:
print("[main] Game started successfully.") print("[main] Game started successfully")
start_emulation_loop() start_emulation_loop()
else: else:
print("[main] Failed to start the game.") print("[main] Failed to start the game")
func start_emulation_loop(): func start_emulation_loop():
""" """

View file

@ -33,16 +33,23 @@ done
write "" write ""
write "My issue now is the following, can you help me to fix it?" write "My issue now is the following, can you help me to fix it?"
write ' 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)
================================================================ [RetroHost] Initializing extension...
handle_crash: Program crashed with signal 11 [RetroHost] RetroHost class registered.
Engine version: Godot Engine v4.2.2.rc2.mono.official (c61a68614e5b030a4a1e11abaa5a893b8017f78d) [RetroHost] Constructor called. Initializing singleton.
Dumping the backtrace. Please include this when reporting the bug to the project developer. [RetroHost] Initialization complete.
[1] /lib/x86_64-linux-gnu/libc.so.6(+0x45250) [0x7ea94c445250] (??:0) [RetroHost] Singleton registered successfully.
-- END OF BACKTRACE -- [main] Entering _ready function
================================================================ [main] File res://cores/genesis_plus_gx_libretro.so exists
Annullato (core dump creato) [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: <null>
[libretro_loader] RetroHost singleton not found!
[main] Failed to start the game
' '

View file

@ -10,17 +10,26 @@ var current_rom : String = "" # Initialize to an empty string
func start_emulation(core_path: String, rom_path: String) -> bool: func start_emulation(core_path: String, rom_path: String) -> bool:
print("[libretro_loader] Starting emulation with core: ", core_path, ", ROM: ", rom_path) 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 # Check if RetroHost is available
if not retro_host: 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 return false
if not core_path: 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 return false
if not rom_path: 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 return false
# Load the core (via RetroHost) # Load the core (via RetroHost)
@ -100,26 +109,37 @@ func _process(delta):
func _ready(): 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.") print("[libretro_loader] _ready: Initializing SubViewport and TextureRect.")
if sub_viewport and texture_rect: if sub_viewport and texture_rect:
print("[libretro_loader] SubViewport and TextureRect initialized successfully.") print("[libretro_loader] SubViewport and TextureRect initialized successfully.")
else: else:
push_error("Error: SubViewport or TextureRect is missing.") push_error("[libretro_loader] Error: SubViewport or TextureRect is missing.")
return 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 # Ensure SubViewport always renders
sub_viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS sub_viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS
print("[libretro_loader] SubViewport set to always update.") print("[libretro_loader] SubViewport set to always update.")
# Use await to call the coroutine print("[libretro_loader] _ready: Waiting for RetroHost singleton...")
var success = await start_emulation("res://cores/genesis_plus_gx_libretro.so", "res://roms/megadrive/Sonic")
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: if success:
print("[libretro_loader] Emulation started successfully.") print("[libretro_loader] Emulation started successfully.")
else: else: