转载:目前看到最好的libdrm tutorial
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!
代码在这里: https://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):
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就可以。