GSOC20 Multiple Controllers
Hello @garbear ,
Actually I ran into another problem while running make-mingwlibs.bat file. It now says that it can't find any openssl file and/or any makefile.
Here is the log file for the error.

ERROR: openssl not found

It looks like openssl wasn't downloaded by the download build deps step.

At this point I usually backup the downloads folder, do a git clean -xdf, then restore the cached downloads and start from the beginning
(2020-03-22, 15:10)garbear Wrote: ERROR: openssl not found

It looks like openssl wasn't downloaded by the download build deps step.

At this point I usually backup the downloads folder, do a git clean -xdf, then restore the cached downloads and start from the beginning

Thank you this worked for me

Also I got how the different topologies are precoded into Kodi and understood thos that you gave. So now I am proceeding over to peripheral.joystick code to understand the lifecycle of a button press and the code part of button mapping.

This may take a while. Also stay safe Smile .

Traversing the code is not a trivial task (ref above). Each vertical group of nodes is an API. The APIs are layered on each other, so you end up with a data flow where the data is transformed at each layer:

1. Starting with operating system APIs
2. Next to joystick driver input in C++ (peripheral.joystick)
3. Converted to C for the binary add-on API
4. Converted back to C++ immediately in Kodi

The data flow is a graph, because you'll notice the presence of nodes, the first being the peripheral add-on (CPeripheralJoystick). You can identify nodes in the code when, instead of a handler, they have a std::vector<handler> and a for loop.

5. At this point in the xbmc/peripherals code, we have driver input (low-level). Each handler in the for loop gets this data, and most transform it to controller input (high-level) using a button map. Each driver input handler can use a different button map, and they can be all be different button maps. Thus, input handlers "request" data in whatever form they want, and a lower layer translates driver input to make it look like that controller's input.

An exception is driver input handlers that operate on raw driver data, such as the button mapper.

6. & 7. From the controller input level, you can see there are still many layers (notice all red boxes have two columns of nodes).

7. - X. Traveling down the "Libretro Core" path, there are still many layers to cross. Not shown in the two binary add-on layers, where data is marshaled to C and back again.
(2020-03-23, 18:52)cool-pants Wrote: This may take a while. Also stay safe Smile .

I'm hunkered down in san francisco. my life: 1. stay home, 2. while (1) { code() };
Sorry to overload this thread with info, but I'm hoping to collect and formalize for documentation later.


Back to graph theory, here's some description of the data flow in the above API layers.

The data at each stage in the flow chart is stored in a tuple (struct). The tuple represents stuff on the controller, and each thing is a node in a graph. In this case, the graph is a fully unconnected graph, because we don't care about how the data is related within the layer.


API layers transform the tuple into another tuple. You can visualize this by putting two controller representations side by side, and drawing lines between things on each controller. When you have a group of nodes on one side, and another group on the other side, with lines between them, this is called a bipartite graph.

If translation happens in one direction, this would be a directed graph. It would likely be a bijection, where one thing is mapped to one other thing. It can also be a surjection, where two things are mapped to one thing. For example, I'm working on surjective button mapping, where both a dpad and analog stick can control a single dpad in libretro.

I challenge you to think of how button mapping can be an injection Smile

The subject of topology refers to studying how things are connected. If you've ridden the subway, you've seen a topological map. This shows how stations are connected, but isn't accurate geographically. It contrasts with a topographical map, which shows accurate geography like trails and mountains.

Primarily, in emulation, we study two different kinds of topology:

  • Button topology: how buttons map from one controller representation to another
  • Wire topology: how controllers are physically connected with wires

An aside: The human perception

I'll share a story from school. I was studying thermodynamics, particularly the problem of how heat moves through a solid object. In three dimensions this yields some pretty unwieldy partial different equations!

Fortunately, there's another approach. We can use a computer to divide the solid into small parts, and compute how heat spreads from part to part. In general, the smaller the parts, the more accurate the result. This computer approach is called Finite Element Analysis (FEA).

Now, there's two main FEA algorithms:
  • One is more accurate, but can diverge and never give a result
  • One is less accurate, but always gives a result

Which do you think FEA software makers use?

The answer is the second, because there's only one thing worse than a wrong result: no result. This drives my study of topology, because the only thing worse than swapped buttons: no buttons. We can use topology to choose a good-enough map for unseen controllers.
Practical application in Kodi

With tolopogy you can start doing some pretty smart things. For example, if tuples are used for points of data at the driver level, we can count the number of buttons, hats and axes. If this exactly matches another tuple's counts, then it's a good-enough assumption that buttons on both controllers are in the same spot and can use the same map.

Mapping physical controllers to virtual controllers to libretro controllers is an N * M * O problem, because we have:

  • Large N physical controllers
  • Large M virtual controllers
  • Large O libretro controllers
  •  N * M * O possible transformations

It's impossible to store N * M maps, let alone N * M * O. Instead, we store this data:

  • Maps of all physical controllers to one virtual controller (peripheral.joystick maps)
  • A single map of one physical controller to all virtual controllers (this one)

Now, using a graph transformation, we can map all physical controllers to all emulated controllers.

We also store this data:

  • A map of several virtual controllers to several libretro controllers (e.g. this one)
  • One such map for all emulators

Apply another graph transformation, and you can map N controllers to M controllers to O controllers, for N * M * O possible mappings.

With topology, we can also view that mockup in a new way. Notice the depth-first player assignment. Players are assigned to controllers with input, and multitaps are skipped. Also notice that we've performed the difficult task of visualizing a tree in a two-dimensional grid. This is called a tree-drawing algorithm. All tree operations are performed recursively, which ramps up the difficulty, but scales to handle weird configurations, like daisy-chaining (hubs with input).

(2020-03-23, 21:22)garbear Wrote: I challenge you to think of how button mapping can be an injection Smile

Well it makes sense for button mapping to be an Injection or One-to-one function as we only need a single button on the physical controller to be mapped to only one subsequent button on the emulated one. Otherwise the whole operation would be chaos. Imagine mapping the A button to be both select and back, which will be confusing both to us and the device as one input is trying to do two opposite operations simultaneously. This is only one of the examples. So, well the button mapping should, or rather, must be injective. Also, though not asked, it could also be surjective or onto, which implies that all the buttons on the virtual emulator must be mapped, which also makes sense as the buttons on a controller are there to be used and an unmapped button will mean that you can't use the function attached to that button in-game. But there also is the option of not mapping surjectively, but it should definitely be injective.

PS: also i talked only about the Physical and Kodi controller interaction, but this will also apply for the Kodi-RetroPad controller interactions.
Also this is my edited proposal with much of the edits you specified before and the knowledge i gained from further studying the code and the resources you provided.

I like how the summary is the two mappings we'll have to consider. Motivation, Benefits and Goals are clear and easy to read. Good use of links. Very relevant experience. It's a strong proposal.
To be honest, I think "Multiplayer", while being synonymous with "Multiple controllers", sounds more impressive and brings better bragging rights, don't you? That said, it's your project, and I'll support whatever name you want the most.
(2020-03-25, 17:24)garbear Wrote: To be honest, I think "Multiplayer", while being synonymous with "Multiple controllers", sounds more impressive and brings better bragging rights, don't you? That said, it's your project, and I'll support whatever name you want the most.
Well yeah Multiplayer does sound pretty amazing and that's the heading I chose for my proposal. I started with the latter as a header to not sound pretentious and tried to keep it as humble as possible but now I switched to "Multiplayer".
I'm just adding my commentation here in order in need to be found later or for anyone who like to discuss.

Regarding the challenge of how button mapping can be an injection i thought that the mapping should either be between same graphs of graphs that each element inside the one graph has only one mapping to the othen one,meaning the different combinations of buttons should not have multiple mappings. (to another graph - to another controller represenation)

To apply that the wire topology should be considered equally.Secondly,the FEA algorithm which always produces a result is better to be used since in software the results lead us to understand the software better in order to debug it or anything else.I understand that not being able to create injections between the graphs we will have O(N*M*O) mapping which is very bad but with injections we can reduce this because we can have same topologys or wire topologys for more than one virtual controller with the same mapping.

This way the code is less and more easy, the algorithms can be applied easier and with less latency while the virtual controllers and all topologies are easier to understand by as humans. Like the FEA algorithm, having a topology for one controller and trying to make it appliable the other controller will give you "results" to percept.
Interesting ideas. I'll expand on the injective button mapping, just for fun (it's not something I'm considering).

Recall the classes of mapping functions:




Surjective button mapping means that multiple things map to one thing. This means both the emulated DPad and analog stick can control the RetroPad DPad. Currently in SNES games, the analog stick does nothing. Remember, doing nothing is bad UX. With surjective button mapping, both emulated features control the DPad, so both analog stick and DPad can be used to move a SNES character.

Which brings me to injective button mapping. This means a SNES controller, with a single DPad, can control both the analog stick and DPad on the RetroPad. The game would see inputs on the "analog" RetroPad on both its DPad and analog stick. E.g. pushing left on the single SNES controller DPad would activate both DPad-left and analog-stick-left on the RetroPad.

The challenge with injective button mapping is that the game sees double input and might go crazy. So, a possible solution is holding the Select button: If unheld, pushing left will send a left DPad, if select is held, pushing left will send a left analog stick.

You could also consider an Xbox 360 controller mapping to many keys on a keyboard based on button combos or holding or whatever.

@GiannisProkopiou toward your goal of "everything emulating everything" - injective button mapping is how a SNES controller with no analog stick can emulate the analog RetroPad with an analog stick. You will need both injection and surjection to handle many buttons to few, and few buttons to many. That's why I think injective button mapping would interest you. Of course, controlling an analog RetroPad with a SNES controller is such a niche case, I think we should stop short of everything emulating everything. Just my opinion, maybe you think your project should include injective button mapping.
@cool-pants you have a good grasp of graphs, so I'll introduce a new concept: generating DIDs (decentralized IDs) for players and persisting their profiles on a decentralized file storage network such as IPFS, Filecoin or Sia.

Logout Mark Read Team Forum Stats Members Help
GSOC20 Multiple Controllers0
This forum uses Lukasz Tkacz MyBB addons.