KWin supports implementing a special compositor. As of version 4.11 KWin provides three compositors:
- OpenGL 1
- OpenGL (ES) 2
with OpenGL 1 and 2 sharing a lot of code. The specific compositors are implemented as a sub class of the abstract base class KWin::Scene and a few more classes. The exact steps are described in this document. As an example for implementing a new Compositor this commit can be used.
Introducing a new Compositing Type
KWin references the various compositors through an enum KWin::CompositingType defined in kwinglobals.h. To add a new compositing type a new enum value has to be added. The enum also operates as a flag type, which allows to have compositor sub-types (c.f. OpenGL1Compositing and OpenGL2Compositing as a sub-type of OpenGLCompositing). Each Compositor should have it's own value which has to be returned by the specific implementation of Scene::compositingType().
The CompositingType is necessary for deciding which Compositor to start when compositing gets initialized. For this the method Options::loadCompositingConfig in options.cpp needs to adjusted. The to be used Compositor is read from the config key "Backend" which has the values "OpenGL" or "XRender". To have another Compositor this needs to be extended and checked for. In addition the Compositor can also be selected by the environment varible "KWIN_COMPOSE" which expects a one character value, e.g. "X" for XRender.
Creating the Compositor
The Compositor is created in Compositor::slotCompositingOptionsInitialized() in composite.cpp. Depending on the CompositingType previously set in the Options a specific sub class is created. The code can either do the complete initialization code of the Scene sub class or just call a static factory method in the Scene sub class. It is recommended to use the factory method pattern as this way the error handling can be kept inside the Scene sub class. It is allowed to return NULL in error case and the Compositor can then fall back to another Compositor or even restart KWin to apply adjusted settings for a different Compositor. In addition the Scene provides a pure virtual method initFailed(). This method is checked if a non-null Scene is provided. In case of the factory pattern the implementing class can just return false, otherwise it should have proper error handling. If this method returns true the Scene will be destroyed again.
Scene is an abstract class providing the bas interface towards the compositing framework. The main functionality of this class is to setup the state to render a frame and to be a factory for other Scene related classes. As the class provides many pure virtual methods it's rather obvious which methods need to be implemented.
Rendering a frame
Rendering a frame is controlled by the virtual method Scene::paint(QRegion damage, ToplevelList toplevels). This method has to perform some setup functionality like creating the stacking order for this frame. It is allowed to extend the damage region before the method calls the parent class's method paintScreen(). This method starts the effect chain for rendering. Once the method returns the frame has been rendered and the Scene should blit it to the screen. Last but not least the method needs to cleanup e.g. clear the stacking order and return the time it took to render this frame. This is required for the Compositor to properly schedule the next frame.
The Scene can limit the frame repainting through the method isLastFrameRendered(). If this method returns false the Compositor will not start the rendering of a new frame. If an implementing class of Scene provides a custom implementation of this method, the Scene should call Compositor::self()->lastFrameRendered() once the frame finished so that a new frame can be immediatelly scheduled if it was blocked before.
The method Scene::paintBackground(QRegion region) is responsible for rendering the background. This normally happens at the begin of the frame rendering. KWin expects the background to be rendered in black fully opaque. The rendering should be restricted to the passed in region - this is true for all methods taking a region argument.
Transformed desktop rendering
If the desktop is rendered with trasnformations the method Scene::paintGenericScreen() will be invoked. The implementing class can use the passed in information to adjust the rendering of this frame (e.g. scaling, translating). KWin expects that translation is performed before scaling is performed! After a frame is rendered the adjustments should be reverted so that there is no state overlap to the next frame.
On X11 compositing is normally performed on the X11 Overlay window. KWin has a class wrapping the functionality and the Scene can make use of it, but does not have to. To make use of the Overlay Window it needs to implement Scene::usesOverlayWindow() and Scene::overlayWindow().