Mupen64Plus v2.0 API Versioning
Contents
Mupen64Plus v2.0 API Versioning
Goal
The Mupen64Plus API versioning scheme was invented to give a more friendly and less confusing experience for users as the various components evolve over time. There are 6 basic components to the Mupen64Plus system, which may be independently built and installed:
- The Front-end UI application
- The Core emulator library
- The Video plugin
- The Audio plugin
- The Input plugin
- The RSP plugin
These components interact with each other in several different ways. The design goal of the versioning scheme is to gracefully handle all situations in which two components support different versions of their common API (due to one component being newer than the other). In particular, each pair of components sharing a common API must discover whether or not they are compatible with each other. They must make this determination early enough in the startup process to inform the user of an incompatibility and gracefully exit the software if necessary without crashing. There are 2 different decisions that pertain to the compatibility determination:
- Major API version. The various API version numbers are 32-bit. The major version number is stored in the upper 16 bits, and the minor version number is in the lower 16 bits. If two components have different major API version numbers, then they are definitely incompatible.
- Minor API version. If two components with a common API have different minor version numbers, then the newer component may decide whether or not it can interact with the older component based upon the older component's version number. The newer component may optionally disable new features and still retain backwards compatibility, or it may refuse to operate with the older component. This decision is left to the component author when new features are added.
Basic Design
In mupen64plus-core/src/plugin/plugin.h, the following macros are defined:
#define RSP_API_MAJOR_VERSION 0x20000 #define GFX_API_MAJOR_VERSION 0x20000 #define AUDIO_API_MAJOR_VERSION 0x20000 #define INPUT_API_MAJOR_VERSION 0x20000
In mupen64plus-core/src/main/version.h, the following macros are defined:
#define FRONTEND_API_VERSION 0x020000 #define CONFIG_API_VERSION 0x020000 #define DEBUG_API_VERSION 0x020000 #define VIDEXT_API_VERSION 0x020000
- When the front-end application calls the CoreStartup() function, it passes it's Core<-->Front-end API version to the core. If the API major version numbers for the core and front-end don't match, the core will return from this function with a failure code of M64ERR_INCOMPATIBLE.
- The Console-UI front-end also checks for API compatibility, during the AttachCoreLib() function call. It is not strictly necessary for a front-end application to verify the API compatibility with the core, since the core will also check during CoreStartup(). However, by doing so, an updated front-end may detect a core library using a newer (but backwards-compatible) API, and enable some extra features as a result of the expanded API.
- At the time each plugin is attached to the core (during CoreAttachPlugin function call), the core checks the version number of the plugin API by calling the PluginGetVersion function. If the major version number of the plugin's reported API (APIVersion & 0xffff0000) does not match the corresponding version number for that plugin type in the core (defined in plugin.h), then the plugin is incompatible and cannot be attached to the core. Currently the plugins have no way to request the major version number required for a particular plugin type in the core library.
- The emulator core exports several different API groups which may be used by the front-end and plugin modules. Currently, these groups are: Front-end, Config, Debug, and Video Extension. A front-end application or any plugin may call the CoreGetAPIVersions() function to retrieve the API version numbers for these groups. Any plugin or front-end which can use any updated (not present in the original "2.0" API) functions in one of these groups should call the core's CoreGetAPIVersions() function (during PluginStartup for a plugin or at core attach time for a front-end) to check the version # of the API supported by the core, and react accordingly.
- All front-ends and plugins should verify API version compatibility for the Config API.
Handling Future Changes
New feature added to a plugin library
If the feature is backwards-compatible with older cores, then plugin API minor version will be bumped. Otherwise, major version number will be bumped. If change is backwards-compatible, then newest core can test the plugin's API version and only enable the feature if present.
New feature added to Core<-->Front-end API
Typically this will happen when a new function or a new feature of an existing function is added to the core. If the older front-ends will still be compatible with newer cores, then the minor version number of the front-end API will be bumped. Otherwise the major version number will be bumped. A newer front-end can check the version of the API supported by the core and choose whether to retain backwards-compatibility with older cores or refuse to interoperate.
New feature added to Core Config API
If older plugins can still use the Core Config API with the new feature, then Config API minor version will be bumped. Otherwise, major version number will be bumped. Newer plugins should check the Core's Config API version and maintain backwards compatibility with older cores if possible.
New feature added to Core Debug API
If older front-ends can still use the Core Debug API with the new feature, then Debug API minor version number will be bumped. Otherwise, major version number will be bumped. Newer front-end applications should check the Core's Debug API version and maintain backwards compatibility with older cores if possible.
New feature added to Video Extension API
This is the most complicated interface, because it involves 3 components: the video plugin, the core, and the front-end application. If older video plugins can still use the newer Video Extension API with the core, *and* newer front-end applications can work with older cores, then the Video Extension API minor version number will be bumped. Otherwise, the major version number will be bumped. Newer video plugins can check the Core's Video Extension API version and maintain backwards compatibility with older cores if possible, otherwise they can refuse and give a compatibility error. Front-end applications (such as the default console-ui) which do not hook into the Video Extension do not need to check the Core's Video Extension API version. However, front-end applications which do hook into the Video Extension must check the API version. If the Core and Front-end have different API major version numbers, then they are incompatible. Also if the Core has a *newer* minor version than the front-end, then they are incompatible. This is a unique restriction, and it must be checked and verified by the front-end; the Core has no way to check this.
Changelog
- Version 2.0.0 is the base for all APIs
- FRONTEND_API_VERSION version 2.0.1:
- added "m64p_command" type "M64CMD_CORE_STATE_SET", handled by CoreDoCommand()
- added "m64p_core_param" type "M64CORE_SPEED_LIMITER", handled by "M64CMD_CORE_STATE_QUERY" and "M64CMD_CORE_STATE_SET" commands
- FRONTEND_API_VERSION version 2.0.2:
- added "m64p_command" types:
- M64CMD_GET_SCREEN_WIDTH
- M64CMD_GET_SCREEN_HEIGHT
- M64CMD_READ_SCREEN
- M64CMD_VOLUME_UP
- M64CMD_VOLUME_DOWN
- M64CMD_VOLUME_GET_LEVEL
- M64CMD_VOLUME_SET_LEVEL
- M64CMD_VOLUME_MUTE
- M64CMD_RESET
- M64CMD_ADVANCE_FRAME
- extend command M64CMD_STATE_SAVE to support saving uncompressed PJ64 savestate files as well as zip compressed
- added "m64p_command" types:
- FRONTEND_API_VERSION version 2.1.0:
- removed "m64p_command" types:
- M64CMD_GET_SCREEN_WIDTH
- M64CMD_GET_SCREEN_HEIGHT
- M64CMD_VOLUME_UP
- M64CMD_VOLUME_DOWN
- M64CMD_VOLUME_GET_LEVEL
- M64CMD_VOLUME_SET_LEVEL
- M64CMD_VOLUME_MUTE
- added new "m64p_core_param" types:
- M64CORE_VIDEO_SIZE
- M64CORE_AUDIO_VOLUME
- M64CORE_AUDIO_MUTE
- M64CORE_INPUT_GAMESHARK
- M64CORE_STATE_LOADCOMPLETE
- M64CORE_STATE_SAVECOMPLETE
- removed "m64p_command" types:
- FRONTEND_API_VERSION version 2.1.1:
- Core command M64CMD_CORE_STATE_SET will now accept M64CORE_VIDEO_SIZE parameter
- will call the video plugin function ResizeVideoOutput()
- Core command M64CMD_CORE_STATE_SET will now accept M64CORE_VIDEO_SIZE parameter
- FRONTEND_API_VERSION version 2.1.2:
- added "M64CMD_SET_MEDIA_LOADER" command to allow frontend to specify several media files (such as GB cartridge ROM and RAM files).
- CONFIG_API_VERSION version 2.1.0:
- add new function "ConfigSaveSection()" to save only a single config section to disk
- CONFIG_API_VERSION version 2.2.0:
- add new function "ConfigHasUnsavedChanges()" to determine if a given Section (or all sections) of the Mupen64Plus Core configuration file has been modified since it was last saved or loaded.
- add new function "ConfigRevertChanges()" to revert changes previously made to one section of the configuration file, so that it will match with the configuration at the last time that it was loaded from or saved to disk.
- CONFIG_API_VERSION version 2.3.0:
- add new function "ConfigSetParameterHelp()" sets the value of one of the emulator's configuration parameters.
- CONFIG_API_VERSION version 2.3.1:
- add new functions "ConfigExternalOpen()" "ConfigExternalClose()" "ConfigExternalGetParameter()" that allows plugins to leverage the core INI parser to read config files.
- DEBUG_API_VERSION version 2.0.1:
- add new function "DebugBreakpointTriggeredBy()" which allows a front-end application to determine which memory address and action (read, write, execute) caused a breakpoint to fire.
- add new function "DebugVirtualToPhysical()" which allows a front-end application to find the physical address which corresponds to a given virtual address.
- VIDEO_API_VERSION version 2.1.0:
- video render callback function now takes a boolean (int) parameter, which specifies whether the video frame has been re-drawn since the last time the render callback was called. This allows us to take screenshots without the On-Screen-Display text
- VIDEO_API_VERSION version 2.2.0:
- add (optional) ResizeVideoOutput function in video plugin. If this function is not present in video plugin, then resizing the output video window will not work.
- VIDEXT_API_VERSION version 3.0.0:
- add VidExt_ResizeWindow() function in video extension. This function is called by the video plugin to notify the window manager (SDL if no video extension is registered by the front-end) that the OpenGL render window size should change.
- add m64p_video_flags parameter to the VidExt_SetVideoMode() function. Currently the flags are only used to notify the window manager that resizing is supported by the video plugin, and it should create a resizable window if possible. This may be extended in the future to support other features.
- VIDEXT_API_VERSION version 3.1.0:
- add VidExt_GL_GetDefaultFramebuffer() function in video extension. This function should be called to get the name of the default FBO.
- INPUT_API_VERSION version 2.0.1:
- add (optional) RenderCallback function to input plugin. This function is called by the core after rendering on screen text (OSD) and before the graphics plugin swaps the buffers. The purpose of this function is to enable the input plugin to draw on screen content, for example buttons in a touch input plugin. If this function is not present the core will ignore it and on screen rendering by the input plugin will be disabled.