Will the vblank-rework branch ever be ready to merge upstream? With some recent work by Michel and myself, I really hope so.
It’s a little distressing that such a simple thing could cause so much trouble. The motivation for reworking vblank in the DRM branch was easy enough: save CPU power by turning off interrupts when possible. Not interrupting the CPU lets it sleep deeper and longer, potentially saving quite a bit of power. Getting rid of the 60 or so vertical blank event interrupts per second when they weren’t needed seemed like a logical first step, and so vblank-rework was born.
Being a good citizen in Linux land often means improving whole subsystems rather than stuffing a bunch of fancy features into individual drivers. Working that way can be harder, but it spreads the benefits wider, and improves Linux as a whole. So my efforts in the vblank-rework branch targetting the generic DRM vblank code, improving the driver APIs and making sure that all drivers could benefit from the new infrastructure, allowing them to disable interrupts when not needed. However, that’s where the “harder” part comes in: every driver needed an update. At first I thought, “Hey this is a neat, new set of APIs, surely everyone will want to use them, I’ll just convert the i915 driver (after some initial work on a radeon based laptop).". Unfortunately, the DRM drivers are in dire need of attention, so after several months of waiting I ended up converting all the drivers myself, though only a few like radeon and i915 actually implement the API fully enough to disable interrupts.
So far, so good. I figured everything was fine and the shiny new branch was ready, so I merged it into the master DRM branch in preparation for an upstream push. Then tragedy struck: Michel’s sharp eyes and testing discovered a potentially fatal bug. While many GPUs provide a frame count register we can use to keep the vblank count accurate (necessary since OpenGL extensions expose an absolute count to applications for some reason), they’re typically only updated at the leading edge of vactive. This means that your application may wakeup at vactive time instead of vblank time, causing ugly tearing; exactly what you’d like to avoid! After a bit of back and forth and a couple of false starts (trying to work around the problem with solutions that turned out to be racy), we decided to go back to using the atomic counter (which is only updated at interrupt time) for wakeups, rather than the hw register, using the latter for keeping the counter accurate across interrupt disable periods.
Which brings us to last week. I hacked up the scheme described above and started testing. As I found and fixed bugs (well actually Michel probably found most of them), I discovered that the API could actually be simplified a bit, and some of the code to compensate for corner cases was no longer necessary, so both the wraparound compensation logic in the pre/post modeset ioctl and the funky accounting we tried to do there could be removed. The result, I hope, is ready for upstream finally.
So where does that leave us, API-wise? Well, on the userland front we have a new ioctl,
_DRM_POST_MODESET arguments. It should be called with _DRM_PRE_MODESET in userland drivers prior to any activity that resets the hw frame counter (typically mode setting). When the mode set completes, it should be called again with
_DRM_POST_MODESET. These calls tell the kernel to account for any lost events so that the vblank count exposed to applications can stay accurate.
On the driver front, there are a few different calls and callbacks:
drm_vblank_get - increase the refcount on the vblank counter
This call just tells the core code that the caller is actively using the vblank counter for something, e.g. scheduled buffer swaps or a blocking vblank wait call.
drm_vblank_put - decrease the refcount
Tell the core you’re done with the vblank counter. When the refcount reaches 0, the kernel knows it can disable the interrupt at some point in the future.
drm_vblank_init - initialize the core vblank code
Should be called at driver load time or IRQ init ioctl time to init the core.
driver.get_vblank_counter - return the current hw frame count
Used by the core code to keep the count accurate across interrupt enable/disable periods.
driver.enable_vblank - enable vblank interrupts on a given CRTC
Used by the core to enable interrupts when the refcount increases.
driver.disable_vblank - disable vblank interrupts on a given CRTC
Used by the core to disable interrupts after a timeout period if the refcount is 0.
With a few simple changes, a given DRM driver can support the new scheme to save power. If you find bugs or have issues with the new APIs, let me know and/or file a bug at bugs.freedesktop.org.
No Pingbacks for this post yet...
|<< <||> >>|