How to set a video mode through libdrm (Part 2)

First of all, you can find the first part here: http://plus.google.com/108656087443346595397/posts/CHNjhmURPm5

This second tutorial on #libdrm / #kms madness is concerned with . Page flipping is the slender brother of . Both require two buffers with the dimensions of the screen to reduce flickering. Using double buffering, there is a fixed (aka backbuffer) and a fixed . Once everything is rendered into the double buffer its contents get flushed, for example with #memcpy , into the #framebuffer. Using page flipping the role of frame and double buffer change every flush, meaning once rendering to the double buffer is complete, it becomes the framebuffer, and the current framebuffer becomes the double buffer. This has the advantage of not having to copy a large chunk of memory, yet it can be only used when the whole screens gets rendered every frame, as each buffer contains the second to last state after each flip.

So, first we need a second framebuffer. Four steps need to be done here: create, map, memory map and add:

drmIoctl(fd,DRM_IOCTL_MODE_CREATE_DUMB,&dumb);
drmIoctl(fd,DRM_IOCTL_MODE_MAP_DUMB,&dn);
back.pointer(mmap(0,dumb.size,PROT_READ | PROT_WRITE, MAP_SHARED,fd,dn.offset));
drmModeAddFB(fd,XRES,YRES,BPP,BPP,dumb.pitch,dumb.handle,&id[1]);

Now, there was a method of page flipping suggested here: http://virtuousgeek.org/blog/index.php/jbarnes/2011/10/31/writing_stanalone_programs_with_egl_and_ (near the end) that essentially flips the framebuffer by resetting the video mode exploiting that the screen timings didn't change. For me this was flickering horribly. Here instead the actual page flipping interface is used. To do the flip there is basically just a single call necessary:

drmModePageFlip(fd,encoder->crtc_id,id[cc=!cc],DRM_MODE_PAGE_FLIP_EVENT,0);

for convenience of usage also the user buffers should be swapped with something like:

frame.swap(back);

Using this as-is will probably result in really bad flickering. Since we have no idea when a flip is complete, we just keep on rendering and flipping, no matter if there is a flip in progress. To determine if a flip is complete we ask the device in charge:

sint l=read(fd,ev,1024);
sint r=0;
sint i=0;
while(i=sizeof(drm_event))
{
⠂drm_event* e=(drm_event*)(&ev[i]);
⠂r=(e->type==DRM_EVENT_FLIP_COMPLETE);
⠂i+=e->length+sizeof(drm_event);
}

This is not the most clean but working method to be able to ask until we get a 'yes'. Here is a more thorough approach: http://github.com/pathscale/libdrm_pscnv/blob/master/xf86drmMode.c (line 750 till end).

This completes the toolbox for page flipping with libdrm / kms. Yet there is one string attached. Having a memory mapped double buffer requires you to make sure nothing gets rendered beyond its bounds, the executable will segfault. On the upside, it is a free memory check.

To see how I use page flipping just check out my code: http://github.com/atcl/xizero/blob/master/src/XZskms.hh

.

(View on Google+)

Posted in gplus.

Post a Comment

You must be logged in to post a comment.