Git Product home page Git Product logo

libretro-backend's Introduction

Libretro API bindings for Rust

Documentation

This crate exposes idiomatic Rust API bindings to the excellent libretro API.

The target audience of this library are emulator authors who want to turn their emulator into a libretro core, which relieves them from the necessity of creating a full blown frontend for their emulator and allows them to concentrate on actual emulation.

In its current state there is still a lot of features missing, nevertheless it should be useful enough to create a basic emulator.

As always, contributions are welcome!

Getting started

Add this to your Cargo.toml:

[lib]
crate-type = ["cdylib"]

[dependencies]
libretro-backend = "0.2"

and this to your crate root:

#[macro_use]
extern crate libretro_backend;

then just implement the Core trait:

struct Emulator {
    // ...
}

impl libretro_backend::Core for Emulator {
    // ...
}

and use a macro:

libretro_core!( Emulator );

For a full example you can check out this file, which is part of my NES emulator Pinky.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

libretro-backend's People

Contributors

agi90 avatar koute avatar pheki avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

libretro-backend's Issues

Development of new bindings.

Hello. I've recently stumbled upon this repo while developing a core for my own emulator, and noticed that this is pretty much dead and the maintainer is not responsive. In light of this, I've decided to create a new organization and repo to create new libretro bindings for rust.

If you'd like to contribute to this effort, e-mail me and I'll get you added to the organization. I don't intend on being the long-term maintainer of these bindings, hence the new org. I'm also going to @ mention a few people that have been active on this repo, in case you get a mention and wonder why.

The new repo is hosted here and the package is already reserved on crates.io.

@michelhe @thieman @ammaraskar @gmosx @HeroicKatora @stewbasic @niclashoyer @FlorianUekermann @mehcode

Core trait misrepresents the lifetime of GameData

A Core is able to access the GameData any time between on_load_game (when it is passed in) until on_unload_game (when it must be returned). However the data seems to be valid only for the duration of the on_load_game call (I don't know if the libretro documentation states this explicitly anywhere). Thus the trait allows use-after-free errors. Consider the following minimal example:

extern crate libretro_backend;

use libretro_backend::*;

const WIDTH: usize = 320;
const HEIGHT: usize = 240;

struct MyCore {
    video: Vec<u8>,
    game_data: Option<GameData>,
}

impl Default for MyCore {
    fn default() -> Self {
        let (video, game_data) = (vec![0x40; WIDTH * HEIGHT * 4], None);
        Self { video, game_data }
    }
}

impl MyCore {
    fn print(&self, label: &str) {
        if let Some(game_data) = &self.game_data {
            if let Some(data) = game_data.data() {
                println!("{}: {:?}", label, data);
            }
        }
    }
}

impl Core for MyCore {
    fn info() -> CoreInfo {
        CoreInfo::new("defect", "0.1").supports_roms_with_extension("txt")
    }
    fn on_load_game(&mut self, game_data: GameData) -> LoadGameResult {
        self.game_data = Some(game_data);
        self.print("on_load_game");
        let info =
            AudioVideoInfo::new().video(WIDTH as u32, HEIGHT as u32, 60.0, PixelFormat::ARGB8888);
        LoadGameResult::Success(info)
    }
    fn on_unload_game(&mut self) -> GameData {
        self.game_data.take().unwrap()
    }
    fn on_run(&mut self, handle: &mut RuntimeHandle) {
        self.print("run");
        handle.upload_video_frame(&self.video);
    }
    fn on_reset(&mut self) {}
}

libretro_core!(MyCore);

$ retroarch --version
RetroArch: Frontend for libretro -- v1.4.1 -- d8855ca --
$ echo blah > text.txt
$ retroarch -L target/release/libdefect.so text.txt 2>/dev/null
on_load_game: [98, 108, 97, 104, 10]
run: [0, 0, 0, 0, 0]
run: [0, 0, 0, 0, 0]
run: [0, 0, 0, 0, 0]
run: [0, 0, 0, 0, 0]
run: [0, 0, 0, 0, 0]

Mark Core struct as pub(crate) instead of [doc(hidden)]

Hi there, we (Rust group @sslab-gatech) are scanning crates on crates.io for potential soundness bugs. We noticed that the Retro struct which allows for some unsafe operations is marked as #[doc(hidden)]:

libretro-backend/src/lib.rs

Lines 208 to 209 in 9248d74

#[doc(hidden)]
pub struct Retro< B: Core > {

However, this still allows one to import this struct in and potentially use it to trigger unsafe operations from safe Rust code. Instead, maybe this struct should be pub(crate) to actually restrict it's usage?

Transmute of `0` to `fn(..) -> ..` is UB

An internal macro (set_callback) uses a transmute to create several different function types. This is UB and indicative of an underlying problem.

libretro-backend/src/lib.rs

Lines 223 to 233 in 9248d74

macro_rules! set_callback {
($output: expr, $input: expr) => (
unsafe {
if $input == mem::transmute( 0 as usize ) {
$output = None;
} else {
$output = Some( $input );
}
}
)
}

According to the documentation of the function type:

Like references, function pointers are, among other things, assumed to not be null, so if you want to pass a function pointer over FFI and be able to accommodate null pointers, make your type Option<fn()> with your required signature.

The comparison might simply never succeed. What was likely intended is to use the types Option<RespectiveFn> for the input argument, and not only for those stored. This might have been enver observed as a possible (and somewhat likely) likely compilation assigns the null pointer directly to the Option field, thus changing the discriminant to the intended None.

As also aluded to in the documentation, the correct type for ffi is also Option<fn(_) -> _ which should be reflected in the exposed C-interface here.

Also unfortunately, the liberal use of unsafe in the macro hides the fact that the assignment to the static mut ENVIRONMENT_CALLBACK is the one that is actually unsafe and strictly speaking would require a form of synchronization, such as using an AtomicPtr.

Use the word content instead of ROM and game

In the libretro API, the word content is used instead of game or ROM. Games aren't the only things that can be loaded, and libretro isn't just aimed at emulation. Not only would it be more consistent if this used the word content, but it would also make more sense.

Illegal instruction on core load when compiled with any optimizations

I'm just starting to investigate this but I figured I'd post it now. I'm developing a core which loads and runs fine when compiled at opt-level=0 (debug level default). However, if I compile it with any other level of optimizations, whether speed- or size-based, I get an illegal instruction core dump as soon as I load the core in Retroarch. This is before actually attempting to load any content, this is when I select "Load Core" from the main menu. I'm seeing this both in a Linux->Windows GNU crosscompile, and in a Mac native compile.

If I don't make progress soon I'll try to come up with a minimal repro, but a larger repro is available now by cloning https://github.com/thieman/exa-rs at commit 6035360da4f74d72705d88c234d4328a7547a291.

I'm also wondering if this may be related to #13.

Support no game cores

Supporting no-game cores should be easy. I didn't send a patch, because there are some decisions to be made. I would suggest adding a support_no_game: bool to CoreInfo and either turning the game_data argument in on_load_game( &mut self, game_data: libretro_backend::GameData ) into an option, or simply setting its fields to None.

retro_get_system_info only valid after retro_init

The Retro::core_info struct which retro_get_system_info reads from is incorrectly only populated after retro_init has been called.

This doesn't matter when starting Retroarch by passing the core and rom as command line arguments. However, if Retroarch 1.5.0 is started by itself and the core is selected from the "Load Core" GUI menu, retro_get_system_info is called before retro_init and returns empty strings for the core name and version. This results in some strange behavior:

  • No core information is shown in the bottom left of the screen.
  • Subsequently, attempting to load content with the core from the "Load Content" menu crashes Retroarch.

I am relatively new to both libretro and rust, so apologies if I have something wrong here. I arrived at the above conclusion due to:

  • Changing the constructor values of core_info from empty strings to "foo", "bar". Under the circumstances above, this results in "1.5.0 - foo bar" showing up in the bottom left of Retroarch when the core is selected, which implies the values are not correctly overwritten in time by the core's implementation of Backend::on_initialize.
  • Adding some println!s to libretro-backend which shows retro_get_system_info being called several times before retro_init

Experimentation was done with https://github.com/koute/pinky and with a minimal core of my own which uses libretro-backend.

Add Keyboard support

This is a very useful library, thank you. Apart from joypads, it would be great to have keyboard support. Any hints how this could be done?

Roadmap Discussion

@koute Really neat start you have here. I was considering doing something like this. I'm wondering how much you're committed to this and where you see this library going.

I see a lot that can be cleaned up, refactored, etc. One big one is keeping closer to libretro terminology.

  • Backend => Core is a big one I'd think

  • libretro-backend => retro-core โ€” Generally I don't see the C convention of "lib-" being carried over into the rust name.

  • Use https://github.com/rust-lang-nursery/lazy-static.rs for the instance mutable static

  • to_cstring( name ) can be replaced with CString::new

  • instead of supports_roms_with_extension("nes") perhaps supports_extensions(&["nes"])

  • Rather than ::on_initialize() perhaps ::info() or ::system_info() implemented like:

fn system_info(&self) -> SystemInfo {
  SystemInfo::new("Pinky")
    .version("0.0")
    .supports_extensions(&["nes", "nes2"])
    .requires_path(false)
}

Any thoughts? I can do things bit by bit in pull requests.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.