May 27, 2014 - KMS and DRM

May 27, 2014

KMS and DRM

Recently, I released a neat game called "The Return", which runs on the Linux Framebuffer Device. However, I had planned to also build a KMS/DRM backend for it. So recently I implemented this KMS/DRM backend.

Working with KMS/DRM is interesting, but not particularly fun. I constrained myself to not using the C library, since that was the original constraint which led to me creating "The Return". This wasn't a big problem for fbdev, since all that has to be done is opening up the device file, some ioctl calls, and then mapping the framebuffer. However, for KMS/DRM, most applications using KMS/DRM use libdrm, but libdrm needs the standard C library, which I rejected. So I spent a lot of time reading through the libdrm source code to figure it all out.
I discovered first of all that KMS/DRM is a lot more complicated than fbdev. This makes sense since it's meant to do more, but it doesn't make my job any easier. In my opinion there is also a lot of room for improvement.
Once I figured out what was supposed to be going on, it shed light on a few issues that I would face later. First of all, the KMS/DRM API expects a lot of things to be stored in dynamically allocated memory, but without the standard C library, there is no malloc, and dynamic memory management is pretty complicated. I worked around this by just statically allocating what I figured would be more than enough memory.
The next problem is more severe. The KMS/DRM API allows you to do a lot of things with your code, sounds good, but it also means you have a lot more things that you have to worry about. Mode Setting (KMS) is basically a method of telling the kernel how you want your graphics card to be set up. You have to do this by first asking for information about the graphics card, like what connectors are available and then checking if anything is plugged in to those connectors, and if so, what are the valid "modes" that you can use. Now a "mode" essentially means the possible dimensions of your display. For instance, I am using 1366x768 on my main screen, and 1024x768 on my external monitor right now. This is important because you have to create the framebuffer at the right size. So far this is all logical, but if you think about it for a little while you might come up with a few questions. For instance, what should I do if I find two displays with different available modes? What criteria should I use to select a mode? If there is more than one active display, which one should my application display on? I haven't come up with a really nice clean solution to these problems yet, but for now what I am doing is checking all the first mode of each connector and picking the one with the largest dimensions. I suppose this is one of the purposes of X11 or Wayland or Mir, to solve some of those issues.
Speaking of X11 (which does it's own KMS), I discovered some fun issues while working on the KMS/DRM code. Namely, like fbdev, I have to switch to an unused tty to run the code, which is no problem. However, while the program is running and the device file is open, it has exclusive control of the device. This means that I cannot switch back to X11 while the program is running, since X will fail to get control. This did not keep me from trying, hundreds of times, and each time the result was the same: X failed to get control of the device and crashed. Which is really wonderful because then I lose all the things I was working on at the time.

Anyways, I finally got the code working and integrated into "The Return". Now the game can be compiled with either KMS/DRM or with fbdev as the backend. I have not yet uploaded this code to the website. The KMS/DRM backend has been tested only on my computer, and I am a bit worried about how it will behave on other machines.
Actually, I am a bit worried about how it behaves on my own machine too. The first time I ran "The Return" with DRM instead of fbdev, I noticed it was ridiculously slow. I made some optimization, and I got it to the point where the delay is almost acceptable (but not acceptable), but the fact remains, fbdev is faster. This may just be due to my particular graphics card and system set up, probably my code as well. It also might just be that DRM has more overhead than fbdev does, which would be very sad.

Anyways, regardless of all the problems I encountered, I wrote up a quick tutorial on how to use the KMS/DRM API and added it to the Linux Low-Level Graphics tutorial on this site. It needs some improvement, and the method I used for selecting the correct mode in "The Return" is different (and probably better) than what I described in the tutorial, but it does work. If you think you can improve on my tutorial, email me at prushik@betteros.org.
Anyways, have fun. That's all for now. Peace!