My favorites | Sign in
Logo
                
Search
for
Updated Sep 08, 2009 by Jake.Stine
Labels: Featured, Phase-Implementation
wxWidgetsCodingStrategies  
PCSX2 Coding Strategies Using wxWidgets

The new trunk of PCSX2 is now based on wxWidgets, and this makes for some pretty significant changes to how the code of PCSX2 is structured and, more importantly, sets up a few rules and guidelines for writing happy wx code that's functional, portable, and thread-safe.

Lean on wx as much as possible

The new wx-based codebase for PCSX2 is designed to 'lean' heavily on wxWidgets, meaning that PCSX2 will whenever possible use wx-provided tools and classes instead of re-inventing our own. This decision was made as it allows us take full advantage of the cross-platform tools offered by wxWidgets, which ensures more correct behavior on Windows and Linux alike and, in turn makes life simpler for all PCSX2 developers.

This means that you should, whenever possible, use the following classes instead of other common alternatives:

There are some exceptions to this last rule:

(any others...?)

Maintain 'Emulation Core' and 'User Interface' Separation

As of the writing of this doc, this topic is still a work-in-progress on the wx branch, but it's something I'm hoping we can trend toward instead of trend away from. The idea is that in an ideal code configuration, the PCSX2 core libraries can be used from 3rd party user interfaces. This is not mean to be a plugin-scope separation! What that means is there there's no need for a plugin standard interface that's built to be version compatible, or that includes plugin-style enumerations or complicated and ugly DLL export mnemonics. It's meant as a static linking scenario only. If a DLL interface is provided in the future, it will be done using a separate project that provides a DLL interface layer to the static PCSX2 core static library. That is, the goal here is not to complicate code, but rather to simplify it and reduce inter-dependent clutter that can wreak havoc on thread safety and also makes future improvements and upgrades more difficult.

Currently however there is no distinct separation between the emulation core and wx-based GUI, since there are still several intertwined dependencies that still need to be dealt with in a nice manner. There are some items in the wxgui branch geared with core/ui separation in mind, however, and these you'll want to be aware of:

The emulator core and GUI are now threaded, which means the GUI cannot simply change the emulator's settings whenever it feels like it. This will result in nasty bugs caused by obscure threading race conditions. To solve this, Core and UI settings have been separated into two structures, Pcsx2Config (for core emu options), and AppConfig (wx-UI options). AppConfig contains its own copy of Pcsx2Config since, as a UI, it needs to maintain both its own options and the options it uses to invoke emulation. The emu core uses its own local copy of settings, however. The core's internal settings copy is called EmuConfig, (defined as extern Pcsx2Config EmuConfig), and should never be read or written to by UI code directly.

Be Careful when Sending Events to Other Windows

There are several ways to send events between windows in wxWidgets, and only one of them is typically the correct way:

// This method ensures cross-platform consistency and thread safety, but cannot be
// used to get a return code.
myWidget->GetEventHandler()->AddPendingEvent( evt );

// This one performs an immediate handling of the event, and should only be used
// if you need a return code, or know for sure the caller is on the Main/GUI thread
myWidget->GetEventHandler()->ProcessEvent( evt );

// The wxApp class does not have a GetEventHandler() so for it you use this:
wxGetApp()->AddPendingEvent( evt );    // safe from any thread
wxGetApp()->PocessEvent( evt );        // safe form GUI thread only

This can be a bit confusing because wx has several other options for sending events, and most of them have caveats as noted below:

// This one works but is depreciated, and can lead to cross-platform inconsistencies:
myWidget->AddPendingEvent( evt );

// This one has the same problem as above.
wxPostEvent( myWidget, evt );

// This one actually works correctly, but might as well just use the more direct
// example of myWidget->GetEventHandler()->AddPendingEvent( evt );
wxPostEvent( myWidget->GetEventHandler(), evt );

... So the moral of the story is: Use GetEventHandler() when possible (basically anything except the wxApp object), and use AddPendingEvent() unless you need a return code and know you're on the main GUI thread.

Guidelines when Using Windows/Linux Specific Code

The simple rule is to not use any windows or linux specific code unless absolutely necessary. Most of the time wxWidgets provisions us with cross-platform alternatives for most tasks, so always make sure to check the wx documentation first. But, of course, there are still cases of advanced coding that wx doesn't cover, and these will need platform specific implementations. For example, there is no direct Linux equivalent of Windows Structured Exception Handling (SEH), and PCSX2 code that uses SEH must either be coded to use Linux signals (if possible) or #ifdef'd out under Linux.

There are two ways to handle separate Windows and Linux implementations

As noted, it's generally preferred to create implementations in platform specific files over using #ifdef. This helps keep code much cleaner and saner, and is more friendly toward code editors/IDEs as well (most editors handle #ifdef poorly, either failing to gray out the unused defines, or by enforcing an ugly tabbing layout that is only suited to function-level codeblock removal). When using platform specific files it's usually preferred to have each filename assigned the platform's tag. Example:

/Windows/WinSpecific.cpp
/Linux/LnxSpecific.cpp

... as this provides a clear identifier to cross-platform programmers which files they're looking at when they use things like Find-in-Files and other global search tools.


Sign in to add a comment
Hosted by Google Code