Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
Tags
(1 edit) (+1)

It is the second week. I continued development on the port by implementing one of the core classes, used by Godot - the OS class. It, as the name suggests, handles a lot of the OS-specific operations, as well as initializes and configures a lot of the servers used by Godot such as the Visual Server, used for rendering.

The most important functions of the OS are:

void OS_PS2::initialize(const VideoMode& p_desired, int p_video_driver, int p_audio_driver)
{
	args = OS::get_singleton()->get_cmdline_args();
	current_videomode = p_desired;
	main_loop = NULL;

	ticks_start = clock();

	rasterizer = memnew(RasterizerDummy);

	visual_server = memnew(VisualServerRaster(rasterizer));

	AudioDriverManagerSW::get_driver(p_audio_driver)->set_singleton();

	if (AudioDriverManagerSW::get_driver(p_audio_driver)->init() != OK)
	{
		ERR_PRINT("Initializing audio failed.");
	}

	sample_manager = memnew(SampleManagerMallocSW);
	audio_server = memnew(AudioServerSW(sample_manager));
	audio_server->init();
	spatial_sound_server = memnew(SpatialSoundServerSW);
	spatial_sound_server->init();
	spatial_sound_2d_server = memnew(SpatialSound2DServerSW);
	spatial_sound_2d_server->init();

	ERR_FAIL_COND(!visual_server);

	visual_server->init();

	physics_server = memnew(PhysicsServerSW);
	physics_server->init();
	physics_2d_server = memnew(Physics2DServerSW);
	physics_2d_server->init();

	input = memnew(InputDefault);

	_ensure_data_dir();
}

void OS_PS2::initialize_core()
{
	ThreadDummy::make_default();
	SemaphoreDummy::make_default();
	MutexDummy::make_default();

	FileAccess::make_default<FileAccessPS2>(FileAccess::ACCESS_RESOURCES);
	FileAccess::make_default<FileAccessPS2>(FileAccess::ACCESS_USERDATA);
	FileAccess::make_default<FileAccessPS2>(FileAccess::ACCESS_FILESYSTEM);

	DirAccess::make_default<DirAccessPS2>(DirAccess::ACCESS_RESOURCES);
	DirAccess::make_default<DirAccessPS2>(DirAccess::ACCESS_USERDATA);
	DirAccess::make_default<DirAccessPS2>(DirAccess::ACCESS_FILESYSTEM);

	mempool_static = new MemoryPoolStaticMalloc;
	mempool_dynamic = memnew(MemoryPoolDynamicStatic);
}

A couple of very important operations take place here. Let us start with the initialize function. Here we set up the different servers used by Godot such as the Physics Server, the Visual Server the Audio Server, etc. This is where we register our Rasterizer. The Rasterizer is responsible for all of the rendering.

At this point, I just wanted to have the thing run without rendering anything so I used a Dummy Rasterizer that does nothing. I would worry about that later down the line.

Now, the second most important function is the initialize_core function. Here we configure OS stuff such as Multithreading, Synchronization, File Access, and Memory.

The PlayStation 2 does support multithreading but to limit the points of failure, I opted to not implement this right now. A bare-bones port to start with that I could extend later down the line.

The PS2 SDK uses functions from the standard C library for working with files. I copied the already existing implementation for Unix and just removed some of the system functions that were not available on the PS2. The SDK is not fully Unix-compatible.

I had to disable rendering at first as I just wanted to see the engine boot. I managed to get my code to compile but I had to turn off many of the features of Godot as I didn’t really need them for my first attempts of porting:

    env["module_cscript_enabled"] = "no"
    env["module_dds_enabled"] = "no"
    env["module_mpc_enabled"] = "no"
    env["module_openssl_enabled"] = "no"
    env["module_opus_enabled"] = "no"
    env["module_pvr_enabled"] = "no"
    env["module_speex_enabled"] = "no"
    env["module_theora_enabled"] = "no"
    env["module_webp_enabled"] = "no"
    env["module_squish_enabled"] = "no"

The engine compiled and I had an ELF file that I could run on the PS2. I fired up the PCSX2 emulator and ran the ELF file. To nobody’s surprise, the thing crashes. I didn’t have a debugger at hand and I saw that it would not be easy to setup one so I opted to use console logs. However, at first, I could just not get PCSX2 to show me any console output. No matter what options I used, there was no output.

I saw that the PS2SDK had debugging utilities that could be used to print text to the screen. So I modified my code to use those functions and to my surprise, I did get the output!

Godot running on PCSX2

Awesome! It was complaining that it could not find files with game data. Godot stores the game resources (textures, sounds, scripts, scenes, etc.) in files with the PCK extension. I quickly exported a data.pck file from a “Hello, world!” project I created with Godot 2.1.6 and placed it beside the ELF file.

I saw that the PS2 supports File IO via the standard libraries so I just copied over the Unix implementation for the FileAccess and DirAccess classes. As their names suggest, they are used to access files and directories on the OS. I had to do a bit of modification as not all Posix functions were implemented on the PS2.

So I ran the game again but to my surprise, the data.pck was still not being picked up. I needed to debug but I had no debugging. “Not a problem. I will use logging!” - I said to myself. But then I realized. Other than the onscreen console, which was running out of space because of what Godot was printing, I had no access to the console. Nor did I know how to output anything.

well, I did some research and initially, it seemed that I could only get the logs on a real PS2 through serial. Yikes!.

But, I saw an option in the PCSX2 debugging window: PCSX Debugging Window Sources Menu

I unticked all options and left just the System out one. I thought that that is what would get my printfs to appear. Boy was I wrong. This took me 3 days to figure out!

It turns out that what I was using for debugging was actually printing to the IOP Console. Who would have figured … Anyway, I started placing logs everywhere to try and figure out what was going on.

As is with these things, it turned out that I just had to read the console carefully. Even if I hadn’t gotten the logs from the console, I could have seen what was wrong:

Unknown device `host`

Well, that is a pickle. Turns out that PCSX2 was using my host machine as a device, however, it was using it only to load the ELF file. After the file is loaded, the host machine data is no longer accessible.

After a log of research, I discovered that I needed to enable the host device feature on PCSX2, which would give me access to the files on my hard drive and more importantly, access to the data.pck file that was right next to the ELF file.

To my surprise, this option was removed in the version of PCSX2 I was using originally - 1.6.0. So, I tried downloading a more recent version of PCSX2. Turns out, there weren’t any versions. Or, at least, I could not find any.

I did some more research and I found out that there was a plugging that allows me to mount an ISO in the USB drive that can be seen by Godot. I set up the plugin, but again, the data.pck file could not be loaded. Turns out, that the plugin worked all along, but the issue lay elsewhere. But that is a topic for the next development log. This concludes the second week of development.