gbm creates BO with wrong pitch when dri3_get_modifiers returns modifiers, causing drmModeAddFB2WithModifiers to fail
Submitted by Hans de Goede
Assigned to Intel 3D Bugs Mailing List
This was first discussed here: xorg/xserver!254 (closed)
Where I came up with a completely wrong fix.
The easiest way to reproduce this is:
- Take a Skylake iGPU (in my case with 2 1920x1080 monitors attached)
- Run Xorg master with the modesetting driver (master is necessary because glamor has support for modifiers enabled only in master)
- Run a recent gnome-shell on top of Xorg
- Run xrandr --fb
<height>changing the width to be 32 pixels larger then necessary (or any other value not a multiple of 64)
- Watch Xorg.log filling with errors like these:
[ 28843.414] (WW) modeset(0): Page flip failed: Invalid argument [ 28843.414] (EE) modeset(0): present flip failed [ 28843.595] (WW) modeset(0): Page flip failed: Invalid argument [ 28843.595] (EE) modeset(0): present flip failed
xorg/xserver!254 (closed) has a completely wrong workaround for this by disabling modifier support when a secondary GPU with outputs is present, but that just happen to cause a fb width which was not a multiple of 64.
As mentioned above the problem can be reproduced on a single GPU. The problem seems to be that when the xserver's dri3_get_modifiers method returns a non-empty modifier list, gbm creates buffer-objects using these modifiers (fine) without taking the pitch requirements into account. Or at least without taking the pitch requirements for using these modifiers on a BO which is to be used as a framebuffer into account. This causes the Present extension flip done with a pixmap backed by this BO to fail (the xserver will fallback to a bitblt in this case).
Fixing this may require new API, since currently when using modifiers it is not possible to indicate that the BO will be used for scanout AFAICT.
Another Xserver level workaround is this:
--- a/hw/xfree86/modes/xf86RandR12.c +++ b/hw/xfree86/modes/xf86RandR12.c @@ -693,6 +693,12 @@ xf86RandR12ScreenSetSize(ScreenPtr pScreen, if (pRoot && pScrn->vtSema) (*pScrn->EnableDisableFBAccess) (pScrn, FALSE);
* Present flipping with modifiers may fail if our screen width is not
* a multiple of 64.
- width = (width + 63) & ~63;
- /* Let the driver update virtualX and virtualY */ if (!(*config->funcs->resize) (pScrn, width, height)) goto finish;
Which works, but meh.