libretro-mirrors / libretro-arb

For proposed improvements to libretro API.
8 stars 2 forks source link

Add "user data" pointer to libretro callbacks and functions #2

Closed heuripedes closed 10 years ago

heuripedes commented 10 years ago

Having a void* argument eases the development of language bindings and libretro clients capable of running multiple cores at once. It also allows proper object-oriented wrappers for the libretro api.

Alcaro commented 10 years ago

Yes, it would indeed simplify stuff.

But we can't just change the functions; doing that would make old cores and frontends incapable of understanding new ones. This is called an ABI break, and Squarepusher has made it very clear that he does not want that.

Additionally, adding new versions of the existing functions through an env call would be a tough problem. We can't just add RETRO_ENVIRONMENT_SET_OO_FUNCTIONS. The only way to know which core called that is to have a handle to the core already, and we can't tell the core which handle to give us from within an env, because we don't know it ourselves either. A quite nasty chicken-and-egg problem. We can't add new functions to the libretro API, either; making them mandatory would be an ABI break, and making them optional sounds infeasible on systems where cores must be linked statically. They could probably be ignored on those systems (you can't have multiple cores in them, anyways; it'd lead to two retro_init in the same program), but then you have two different ways to do the same thing, both mandatory, and that would be quite a mess. We could take an unrelated function and repurpose one of the inputs to "do you support the new callbacks?" (retro_get_memory_data(65535), for example, can be defined to a void* and a new environ callback for the core to use). It would work, but redefining functions in that way is quite ugly.

However, there is a way without making a mess out of the libretro API: Set a global variable when you enter retro_set_environment and use it in the new callback.

But now you already have a handle to the core to use from within the callbacks. What do you need the extra void* for?

tl;dr: There is a fully functional way to work around this (see the two paragraphs above), and doing it properly would be extremely tough. While it is one of the first things I'd ask for if libretro gets rewritten, adding it to the current API would not be worth the effort.

Gu1 commented 9 years ago

Hey. I see this issue will be considered for the libretro v2, so I thought I should contribute and give some feedback. With Phoenix, we are in the situation described by heuripedes: Phoenix is a C++ libretro frontend and we had to "work around" the lack of userdata void pointer passed to the callbacks in our code. We currently have implemented a solution similar to what Alcaro suggested: we keep global pointers to the necessary object(s). This is far from elegant. One of the drawback is that we cannot currently load/run multiple cores easily. One way we could fix this would be to have each core run in a separate thread and make the global pointer thread-local... Again, this is not necessarily a very elegant solution, and could be greatly simplified by just having each callback take a userdata pointer. This should IMO be considered for inclusion in the future version of the libretro API.

On the implementation side, I guess the obvious way to do this would be to add a second (void) parameter to the function registering callbacks: https://github.com/libretro/libretro-arb/blob/c9c57b0e36d9ea09e327bf4f2c133f84ae6ce78e/libretro.h#L1830 And add a last (void) argument to the callbacks: https://github.com/libretro/libretro-arb/blob/c9c57b0e36d9ea09e327bf4f2c133f84ae6ce78e/libretro.h#L1782