http://dvdhrm.wordpress.com/2012/09/13/linux-drm-mode-setting-api
http://dvdhrm.wordpress.com/2012/12/21/advanced-drm-mode-setting-api
The Direct Rendering Manager (DRM) is a subsystem of the linux kernel that manages access to graphics cards (GPUs). It is the main video API used by X.org‘s xserver and the xf86-video-*video drivers. However, it can also be used by independent programs to program video output without using the xserver or wayland. In the past most other projects used the much olderfbdev API, however, with more and more drivers being added to the DRM subsystem, there is really no reason to avoid DRM on modern computers, anymore. Unfortunately, there hasn’t been any documentation of the DRM API, yet.
DRM-Modesetting HowTo
I have written a short introduction into the DRM mode-setting API, which can be found on github. It is a full C-file with detailed comments on what is needed to perform simple mode-setting with the DRM-API. I embedded the documentation directly into the source file as this makes reading a lot more convenient:
https://github.com/dvdhrm/docs/blob/master/drm-howto/modeset.c
This document does not describe the whole DRM API. There are parts like the OpenGL-rendering-pipeline, which are driver-dependent and which should almost never be accessed outside of the mesa-3D implementation. Instead, this document describes the API which is needed to write simple applications performing software-rendering similar to fbdev but with the DRM API.
Furthermore, this document is not free of errors. So please contact me if something is wrong, if essential parts are missing or if you intend to extend this documentation.
More tutorials will follow, including “DRM double/triple-buffering”, “DRM vsync’ed pageflips”, “DRM hardware-accelerated rendering”, “DRM planes/overlays/sprites” and more.
I hope you enjoy this short introduction.
=========================================
I recently wrote a short How-To that introduces the linux DRM Mode-Setting API. It didn’t use any advanced techniques but I got several responses that it is a great introduction if you want to get started with linux DRM Mode-Setting. So I decided to go further and extend the examples to usedouble-buffering and vsync’ed page-flips.
The first extension that I wrote can be found here:
https://github.com/dvdhrm/docs/blob/master/drm-howto/modeset-double-buffered.c
It extends the old example to use two buffers so we no longer render into the front-buffer. It reduces a lot of tearing that you get when using the single-buffered example. However, it is still not perfect as you might swap the front and back buffer during a scanout-period and the display-controller will use the new buffer in the middle of the screen. So I extended this further to do the page-flip during a vertical-blank period using drmModePageFlip(). You can find this example here:
https://github.com/dvdhrm/docs/blob/master/drm-howto/modeset-vsync.c
This example also shows how to wait for page-flip events and integrate it into any select(), poll() orepoll based event-loop. Everything regarding page-flip-timing beyond that point depends on the use-cases and can get very hard to get right. I recommend reading Owen Taylor’s posts #1 and #2 on frame-timing for compositors.
There are still many more things like “DRM hardware-accelerated rendering”, “DRM planes/overlays/sprites”, “DRM flink/dmabuf buffer-passing” that I want to write How-Tos for. But time is short around Christmas so that’ll have to wait until next year.
Feedback is always welcome and you can find my email address in all the examples. Happy reading!
代碼在這裡: http://files.cnblogs.com/super119/libdrm-tutorial.zip
原文中有一些feedback,也值得一看。
在modeset-double-buffer-vsync.c中,有一個bug,就是在cleanup之前,沒有wait上一次的page flip結束,這樣就有可能導致雖然我們執行了cleanup,恢複了saved crtc,但是後續的page flip又重新繪製了一螢幕的顏色,最終導致回不去程式執行之前的介面了。所以,在main函數的modeset_cleanup之前,需要添加這樣一段代碼(變數vbl的類型是drmVBlank):
/* Wait VBlank before cleanup. This avoids set crtc in the
middle of a page flip. */
vbl.request.type = DRM_VBLANK_RELATIVE;
vbl.request.sequence = 1;
ret = drmWaitVBlank(fd, &vbl);
if (ret != 0) {
fprintf(stderr, "drmWaitVBlank (relative) failed ret: %i\n",
ret);
/* Anyway, goto cleanup. */
}
理論上來說,kernel的drmModeSetCrtc應該去負責cancel pending的page flip,這樣就不需要userspace來考慮這些問題了。而事實上,set crtc這個工作每個driver的做法是不一樣的。根據原文作者的描述,i915 driver是沒有上述問題的。而我在我的ASUS筆記本上(ATI顯卡,radeon開源驅動)就有這個問題。
所以,理論上來說,我們不需要WaitVBlank這個邏輯,但是目前看來,我們需要(相當於一個workaround)。
不過,wait vblank的方式不是一個好的解決方案,理由是:
1. wait vblank無法指定哪個CRTC
2. 要wait多少個vblank才算OK?
所以,和作者David討論了之後,還是採用wait page flip complete的方法較好。也就是像代碼中一樣,使用select來得知page flip complete.
此外,我還發現作者代碼中,find crtc那個函數,目前是通過encoder的possible_crtcs來選定一個crtc。這樣做可以,但是有可能在最終set crtc的時候會觸發fullmode modeset。因為我們可能改變了encoder, crtc原來的配對。其實我們需要改變要顯示的framebuffer而已。為此,我的建議是,首先check encoder的crtc_id是不是有效,如果有效直接使用。如果無效表示該encoder還沒有crtc配對,那麼就使用possible_crtcs來匹配一個。
最後,find crtc函數中還有一個bug,判斷crtc >= 0,事實上,crtc是unsigned int,這個if永遠成立。所以,可以將crtc = -1改成crtc = 0(因為0也是illegal value),然後判斷crtc是否是0就可以。