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"
// 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<RetroHost>();
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());
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();
}
}

View file

@ -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<godot::Image> 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);
}
}

View file

@ -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():
"""

View file

@ -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: <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:
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: