Graphics

KMS Moves the Screen Into the Kernel

My test laptop changes display modes several times while booting: firmware text, a console mode, the X server’s preferred resolution, and sometimes another mode after resume. Each transition blanks the screen long enough to make me wonder whether the machine is considering a different profession.

Kernel mode setting moves responsibility for configuring display modes into the kernel graphics driver. Traditionally the X server performed that setup from user space. With KMS, the kernel knows about connectors, CRTCs, encoders, framebuffers and modes early enough to establish the display before X starts.

That early ownership makes boot transitions smoother, but the architectural benefit is larger. Suspend and resume already require kernel coordination with devices. If display state is also managed there, restoration does not depend on a particular user-space server reconstructing everything after the fact. Panic and virtual-terminal paths can retain a usable framebuffer as well.

The Direct Rendering Manager interface exposes the resources to user space. A display server can discover connectors and available modes, choose how framebuffers map to scanout hardware, and request changes through a common kernel boundary. The kernel arbitrates access to the device rather than allowing unrelated programs to reprogram it optimistically.

KMS also fits the broader memory-management work in graphics drivers. Rendering buffers and scanout buffers share hardware constraints, and transitions between them need synchronization. Putting mode setting beside DRM’s device and buffer management reduces the number of components that must agree through private arrangements.

My Intel machine with a recent kernel now reaches its native mode earlier and switches to X with less flashing. Resume has also become more predictable. This is not universal evidence. Driver support varies, hardware contains creative surprises, and a failed early mode set can replace a merely ugly boot with a completely dark one.

Debugging changes too. Problems that once belonged entirely to the X log may now begin in kernel messages and driver parameters. Distributions need rescue paths and conservative defaults while support matures. The mechanism is better placed, but moving code into the kernel also raises the cost of mistakes.

I strongly prefer KMS as the long-term division of responsibility. Display hardware is a shared device whose state matters before, during and after the graphical session; the kernel is the natural owner. For current machines I enable it where the driver is known to work and keep a boot option that disables it. Architectural conviction is comforting, but a visible console is more immediately useful.

When Rendering Bugs Move

A Qt application of mine began drawing stale text after I scrolled a custom widget. The bug appeared only with desktop compositing enabled, so I immediately blamed the driver. Then I ran it on a different card and saw the same stale text in a slightly different place.

My naive fix was to call update() repeatedly after scrolling. That reduced the frequency without curing it. Repainting more often can hide an invalid region briefly, but it cannot make incorrect geometry correct.

I reduced the widget until it painted only two rectangles and a label. The problem remained when one rectangle moved outside the area returned by the widget’s internal item bounds. My clipping assumptions were wrong: I invalidated the old logical rectangle but painted a pen and text extending beyond it. Compositing changed timing and exposure enough to reveal the mistake more reliably.

After expanding the dirty region to include every painted pixel, both drivers behaved. I then tested without compositing, with XRender compositing and with OpenGL compositing. That matrix is useful because a defect that follows one backend suggests a different layer from a defect that follows the application everywhere.

Adding a plain background behind the moving item made stale areas obvious and gave the reduced test a result anyone could recognize immediately.

Driver debugging still requires exact information. Card family, kernel module, X driver, Mesa version, colour depth and compositor backend can all matter. “Latest driver” is not a version, especially a week later. A minimal program is worth far more than a description of a large application that sometimes looks odd.

The most useful distinction is between wrong commands and wrong execution. If the application issues the wrong clipping, geometry or lifetime operations, changing drivers may only move the symptom. If a tiny correct sequence fails on one driver and succeeds elsewhere, the driver report becomes persuasive.

My practical conclusion is to simplify before assigning blame. Disable layers one at a time, record the exact matrix, and inspect the application’s painted bounds even when hardware acceleration appears implicated. Graphics stacks are complicated enough without accusing the innocent portion first. Unfortunately, every portion has previous convictions.

Chasing Black Windows

After a driver update, newly opened windows sometimes became black under KWin’s OpenGL compositor. The same windows were fine with XRender. Turning off every effect changed nothing, which at least got the animations out of the suspect list.

The useful split was the texture-from-pixmap path. Under X11 compositing, the server redirects a window into a pixmap. KWin’s OpenGL path then uses the driver’s texture-from-pixmap support to bind that pixmap as a texture for the scene. XRender composites the pixmap through a different route. Applications had painted the right pixels; the OpenGL path was failing to present them.

I could make it happen by opening two terminals, covering one, and uncovering it. Damage arrived, but the exposed window stayed black or returned in strips. Switching to the previous driver fixed that exact sequence. The newer driver also behaved if I disabled its acceleration option, slowly.

That made a much better report than “KWin draws black windows.” I included the X server, Mesa, kernel and driver versions, the OpenGL backend, hardware identifiers, and the short cover/uncover sequence. I also noted that XRender worked. That last fact tells a driver developer far more than a screenshot of a black rectangle.

Screenshots were awkward: some captured the correct window even while the display showed black. The redirected pixmap could be fine while the texture or final scanout was stale. A camera photo was ugly but honest.

I am using XRender for normal work and keeping the failing setup available for testing. Reinstalling KWin would only replace the code that asks the driver to bind the same pixmap. The break is farther down the path, and now there is a reproducible way to reach it.

KWin Compositing on Old Hardware

I enabled KWin’s compositing effects on an older Radeon card tonight. Transparent windows appeared, shadows looked convincing, and moving a terminal promptly turned into an interpretive dance performed at twelve frames per second.

My first response was to disable individual effects at random. Wobbly windows went first, mostly because they looked guilty. Performance improved slightly but resizing still left corruption around the window border. Turning transparency off helped nothing. The decorative suspects had excellent alibis.

The real path is longer. Applications draw their windows, the X server and driver place those results in off-screen storage, and the compositor combines them into the screen image using either OpenGL or XRender. A problem in buffer handling, texture-from-pixmap support, synchronization or damage reporting can therefore resemble a slow effect even when the effect itself does almost no work.

Switching KWin from OpenGL to XRender removed the corruption but used more processor time during movement. That points at the OpenGL driver path rather than at shadows. With a newer Mesa package, OpenGL stopped leaving fragments behind, although it still paused occasionally when opening a large window. Direct rendering tests were useful only as a basic check; a spinning gear is not a compositor workload, no matter how hypnotically one watches it.

I also discovered that forcing every optional visual feature together makes diagnosis unnecessarily difficult. I returned to a plain session, enabled compositing with only shadows, then added effects one at a time. Keeping notes about the backend and driver version made the results reproducible instead of merely emotional.

Compositing is not just confectionery. Drawing the final desktop from managed window images can eliminate ugly exposure repainting and enables useful feedback such as smooth task switching. But it places a great deal of trust in graphics paths that have not received identical testing across cards.

For this machine, XRender is presently the boring and usable choice. OpenGL is the interesting test choice. KWin should detect hopeless combinations conservatively, and drivers must improve before effects can be assumed safe. My conclusion is to report corruption with the exact card, driver and backend, not “KDE is slow.” The latter may feel satisfying, but it gives a developer roughly the diagnostic value of a weather complaint.

Learning Graphics View the Slow Way

I wanted to draw a simple network diagram: a few hundred boxes, some labels, and lines joining them. My old version used a custom widget with a large paintEvent(). It worked until I added selection, dragging and zooming. Then every mouse press became a small geometry examination, and every repaint redrew the universe.

Qt 4.2 already had Graphics View, but I postponed learning it because the three principal classes sounded like bureaucracy. This week I finally moved the diagram to QGraphicsScene, QGraphicsView and a handful of QGraphicsItem subclasses. Naturally, my first implementation reproduced most of the mistakes from the custom widget, only with newer nouns.

I created every item at viewport coordinates and moved them whenever the scroll bars changed. That made scrolling jitter, selection rectangles miss their targets, and zooming move the diagram away from the mouse. I then tried compensating with more coordinate conversions. By noon I had code converting a point from the view to the scene, back to the view, and possibly into a neighbouring dimension.

The useful idea is that the scene owns a stable logical coordinate system. Items live in scene coordinates, while the view is merely one camera onto that scene. Scrolling and zooming alter the camera transform; they should not rearrange the objects. Mouse positions arriving at the viewport can be mapped into the scene once, at the boundary, and item-local coordinates can be left to the item.

After removing my scroll-bar corrections, panning became smooth. Scaling the view around an anchor also stopped corrupting the stored positions. More importantly, a second view could display the same scene at a different zoom without duplicating the graph. That one experiment explained the separation better than the class names did.

Painting required another correction. My naive item painted outside its boundingRect() to make room for a shadow. Sometimes the shadow remained on screen after the item moved, producing a trail that looked like a very cheap supernatural effect. The scene uses the bounding rectangle to decide what may need repainting and which items intersect an area. If the paint escapes that promise, the scene has no reason to clean it up.

I expanded the rectangle to include the pen and shadow, then supplied a tighter shape() for hit testing. Those two concepts need not be identical. The bounding rectangle should be cheap and conservative; the shape can describe the clickable outline more accurately. With that split, selecting a line no longer required clicking somewhere in its enormous rectangular aura.

Performance was my next concern. I assumed one item per node, label and connector would necessarily be slower than one giant paint function. At first it was, because each node recomputed text dimensions and connector paths during every paint. Caching those values when the data changed made a larger difference than reducing the item count. The view can already avoid painting items outside the exposed region, something my giant widget did not do intelligently.

There are still choices rather than magic switches. Device-coordinate caching helps items that do not change but are viewed repeatedly; it is less attractive for items constantly transformed. Indexing the scene accelerates lookup in a mostly stable diagram, but updating an index while thousands of objects move can cost more than a simple scan. The correct setting depends on whether the scene behaves like a map or like a box of agitated insects.

The new event handling is also cleaner. Instead of asking every object whether a mouse point belongs to it, I let the scene deliver events to the topmost suitable item. Movable and selectable flags cover ordinary interaction. A custom item only handles a mouse event when its behavior is genuinely special. This removed an entire home-grown selection system, including one bug where hidden nodes could still be dragged.

Qt 4.3 adds useful refinements, but the important lesson is already present: Graphics View is not a faster canvas. It is a retained scene with explicit geometry, coordinate mapping, event delivery and multiple views. It rewards honest descriptions of where an item is and what it paints. Lie about either and it retaliates with artifacts that appear random but are, annoyingly, deserved.

My practical conclusion is to use a plain custom widget for drawings that are truly one object and have simple interaction. Once the drawing contains independent things that move, select, overlap or need more than one view, Graphics View earns its three-class introduction. Start in scene coordinates, keep bounding rectangles accurate, cache computations rather than blindly caching pixels, and let the framework perform the hit testing. It is less code, but only after deleting the code written to defeat it.