Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhanced Drive API (RFC) #108

Open
hiddenasbestos opened this issue Mar 10, 2019 · 5 comments
Open

Enhanced Drive API (RFC) #108

hiddenasbestos opened this issue Mar 10, 2019 · 5 comments

Comments

@hiddenasbestos
Copy link
Contributor

hiddenasbestos commented Mar 10, 2019

Hi, this is a design/specification (and request for comments) for an enhanced drive API for LibRetro cores.

The current LibRetro API defines a single anonymous drive. While this is sufficient for consoles like the PlayStation, it is not suitable for describing the more complex and varied configurations of home computer systems such as the C64, Apple ][ and Amiga, etc.

This new API introduces a mechanism for cores to tell the front-end about an arbitrary number of independent "drives" each with additional meta-data to both identify the drive with a system specific name (e.g. "DF0") and generally describe the kind of drive (e.g. 3.5" floppy, DVD drive, etc.) to allow for correct iconography and terminology such as disk/disc, etc. Also with an API to control the state of the drive and to request content data be loaded into it.

The API is a recognisable mix of the controller API and existing disk control interface.

Drive

A drive is the generic name used to describe any media storage device that can be loaded with content stored on the host computer in a core-specific or standardised image file format.

A drive can represent a wide range of devices such as a tape cassette, floppy disk, hard disk, ROM cartridge, memory stick, etc.

A drive can accept only one content file at a time. It is the front-end's responsibility to implement "CD multi-changer" functionality for multiple disk titles.

The core provides a list of acceptable content file extensions on a per-drive basis to allow for mixed media support (e.g. .TAP files limited to just the cassette drive).

Drive States

A drive can be in one of the following 6 states.

RETRO_DRIVE_STATE_INVALID,
The drive does not exist, the index used to specify it is invalid.

RETRO_DRIVE_STATE_CLOSED,
The drive is connected but empty and also unavailable for new content to be loaded. The simulated drive mechanism (e.g. CD tray, cassette door, etc.) is considered to be closed/locked in this state. Requesting a RETRO_DRIVE_STATE_OPEN state may allow content to be loaded if the core permits it. This state allows the core to forbid media insertion on this drive. This is the recommended default state for drives on start-up.

RETRO_DRIVE_STATE_OPEN,
The drive is empty and available for new content to be loaded. The simulated drive mechanism (e.g. CD tray, cassette door, etc.) is considered to be open/unlocked in this state.

RETRO_DRIVE_STATE_LOADED,
The drive has content loaded into it and is operating correctly, able to read and/or write data as the core decides. This state is typically set by the core automatically after a call to the retro_drive_load_content function. The front-end must maintain a consistent pointer to any allocated memory for content supplied via an in-memory buffer.

RETRO_DRIVE_STATE_REMOVED,
The drive has been physically disconnected from the system. It is not available for content to be loaded and cannot be accessed by the core. It is implied that the removal of the drive has also emptied it of any media/content. This drive can be hidden by the front-end until potentially re-instated via a state change to RETRO_DRIVE_STATE_OPEN or RETRO_DRIVE_STATE_EMPTY.

RETRO_DRIVE_STATE_ERROR,
The drive has failed but is in a recoverable error state. This state is for use by the core to report when invalid data has been encountered such as a bad sector, or a host file error has occurred. This condition can be addressed by requesting a RETRO_DRIVE_STATE_OPEN or RETRO_DRIVE_STATE_REMOVED state transition.

Note that some states are not permitted for certain drive types, the core determines whether a requested state transition is permitted and has the final say on which states are used / reported to the front-end. Drive state should not be assumed by the front-end.

Drive API

struct retro_drive_description
{
   const char* desc;

/* [OPTIONAL] Short core specific identifier for the drive for human presentation.
A system without a named drive (such as a PlayStation) should use NULL.
e.g. a DOS machine might use "A:" for a floppy drive. The core is required to keep this pointer valid
while loaded or until a new retro_drive_description array is submitted to the front-end.
*/

   unsigned media_id;

/* Describes the kind of drive and media this drive accepts for human usage. Used to allow the front-end to describe it more accurately. For example being able to use disk or disc correctly, or to draw a suitable icon in a menu.
The value is specified as a main type in the low byte and a sub-type in the high byte. A sub-type of 0 mean generic or not-applicable. Main and sub types are given below as RETRO_MEDIA_xxx constant definitions.
For sub-types that are super-sets of lesser types, specify the maximum supported or most common media type - e.g. A PlayStation 2 would specify RETRO_MEDIA_DISK_DVD even though it can also accept CDs. */

   const char* valid_extensions;

/* Same definition as retro_get_system_info(). */

}

A structure describing a single drive in the system.


Media class constants

#define RETRO_MEDIA_CLASS_SHIFT            8
#define RETRO_MEDIA_CLASS_MASK             ((1 << RETRO_MEDIA_CLASS_SHIFT) - 1)

/* media classes */

#define RETRO_MEDIA_GENERIC                0
#define RETRO_MEDIA_CASSETTE               1
#define RETRO_MEDIA_FLOPPY                 2
#define RETRO_MEDIA_DISC                   3
#define RETRO_MEDIA_HDD                    4
#define RETRO_MEDIA_CARTRIDGE              5
#define RETRO_MEDIA_CARD                   6

/* media sub-classes */

#define RETRO_MEDIA_FLOPPY_8                (( 1 ) << RETRO_DEVICE_TYPE_SHIFT)
#define RETRO_MEDIA_FLOPPY_5_1_4            (( 2 ) << RETRO_DEVICE_TYPE_SHIFT)
#define RETRO_MEDIA_FLOPPY_3                (( 3 ) << RETRO_DEVICE_TYPE_SHIFT)
#define RETRO_MEDIA_FLOPPY_3_5              (( 4 ) << RETRO_DEVICE_TYPE_SHIFT)
#define RETRO_MEDIA_FLOPPY_NINTENDO_FDS     (( 5 ) << RETRO_DEVICE_TYPE_SHIFT)

#define RETRO_MEDIA_DISC_LASER              (( 1 ) << RETRO_DEVICE_TYPE_SHIFT)
#define RETRO_MEDIA_DISC_CD                 (( 2 ) << RETRO_DEVICE_TYPE_SHIFT)
#define RETRO_MEDIA_DISC_GDROM              (( 3 ) << RETRO_DEVICE_TYPE_SHIFT)
#define RETRO_MEDIA_DISC_DVD                (( 4 ) << RETRO_DEVICE_TYPE_SHIFT)
#define RETRO_MEDIA_DISC_MINI_DVD           (( 5 ) << RETRO_DEVICE_TYPE_SHIFT)
#define RETRO_MEDIA_DISC_HD_DVD             (( 6 ) << RETRO_DEVICE_TYPE_SHIFT)
#define RETRO_MEDIA_DISC_BLURAY             (( 7 ) << RETRO_DEVICE_TYPE_SHIFT)

#define RETRO_MEDIA_HDD_IDE                 (( 1 ) << RETRO_DEVICE_TYPE_SHIFT)
#define RETRO_MEDIA_HDD_SCSI                (( 2 ) << RETRO_DEVICE_TYPE_SHIFT)
#define RETRO_MEDIA_HDD_ACSI                (( 3 ) << RETRO_DEVICE_TYPE_SHIFT)

#define RETRO_MEDIA_CARD_SD                 (( 1 ) << RETRO_DEVICE_TYPE_SHIFT)
#define RETRO_MEDIA_CARD_SEGA_MYCARD        (( 2 ) << RETRO_DEVICE_TYPE_SHIFT)
#define RETRO_MEDIA_CARD_HUCARD             (( 3 ) << RETRO_DEVICE_TYPE_SHIFT)


struct retro_drive_info
{
   const struct retro_drive_description *drives;
   unsigned num_drives;
};

A container structure similar to struct retro_controller_info


#define RETRO_ENVIRONMENT_SET_DRIVE_INFO

Used to specify a pointer to a retro_drive_info structure


typedef unsigned (RETRO_CALLCONV * retro_drive_get_state_t)(unsigned drive_index);

/* Returns a RETRO_DRIVE_STATE_xxx value for the drive.
drive_index is the logical index from the retro_drive_info array.
Invalid indices should return RETRO_DRIVE_STATE_INVALID */

typedef bool (RETRO_CALLCONV * retro_drive_request_state_t)(unsigned drive_index, unsigned state);

/* Request a state transition for this drive, returns true if successful.
The core is free to ignore any state request. */

typedef bool (RETRO_CALLCONV * retro_drive_load_content_t)(unsigned drive_index, struct retro_game_info* content);

/* Submit content for the given drive index. Returns true if successful, however the front-end should check for RETRO_DRIVE_STATE_ERROR for subsequent errors during execution.
For data buffers, the core should NOT take ownership of the given pointer. The F-E should check for a state being other than RETRO_DRIVE_STATE_LOADED before freeing this memory. */


struct retro_drive_control_callback
{
   retro_drive_request_state_t request_state;
   retro_drive_get_state_t get_drive_state;
   retro_drive_load_content_t load_content;
};

A structure to contain the control callback function pointers.


#define RETRO_ENVIRONMENT_SET_DRIVE_CONTROL_INTERFACE

Used to specify a pointer to a retro_drive_control structure.

@andres-asm
Copy link

libretro/RetroArch#7876

@andres-asm
Copy link

andres-asm commented Mar 10, 2019

I had a similar idea.
Not sure if better is worse.

In my idea there are no pre-defined classes, it would work more like subsystems (I think that's better/more future proof).

I didn't think the "drive states" would matter, other than empty or filled, pretty much anything in between is just internal behavior and not too relevant to the frontend.

Sadly I don't think there is any traction / anyone driving the API forward so it would have to be either me or you submitting a fully functional PR is we want to get anywhere with this.

@hiddenasbestos
Copy link
Contributor Author

hiddenasbestos commented Mar 10, 2019

Hi, thanks for responding. I'm glad its not me to see this area of the API as a having need for improvement.

I'll take a look at your suggestion (sorry I didn't find it myself, but I have your link now) At first glance it's not too dissimilar and probably 'media' might be a better name. I hadn't really considered the memory card management side of things, but that makes a lot of sense to incorporated as part of a new 'drive' or 'media slot' system.

Your point on traction/interest might be a big problem. My concern is taking this (or yours, or any idea like it) from a concept to reality will require some help. I could handle editing cores to conform to it but the need to implement the front-end side of this in RetroArch (plus, full disclosure, my own front-end) and that adds up to too much work for me alone.

@hiddenasbestos
Copy link
Contributor Author

hiddenasbestos commented Mar 10, 2019

One way to make progress might be to take advantage of my own eco system around Grid Cartographer (it's map drawing software and a LibRetro front-end in-one) with its own core forks + downloads,

I could implement a new drive/media API as an experimental branch outside of RetroArch as a proof of concept. Update a test core to support it (e.g. my customers would love better Amiga support, so that might be a good candidate). It would be a core without RetroArch compatibility at first, but would provide the back-end needed to help develop and test the RetroArch front-end in future.

Should some alternative mechanism be decided upon and implemented in RetroArch in the mean time I could update my cores to get back in sync. If nothing happens at least my customers get something they can use \/ :) \/

@andres-asm
Copy link

I figure finishing up the spec is enough and describing the implementation is enough.
I don't see why a new env callback needs to be hooked completely to RA to be approved, wrestling RA is difficult, it took like 3 years for subsystem to have a full implementation on the RA side (and parts of it might be incorrect).

I have no API writing experience, I just know my way around RA and libretro, so I'd say.... let's have a go at it (API / core side) and we'll see what happens.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants