eglfs: allow forcing an overlay plane

Add a QT_QPA_EGLFS_KMS_PLANE_INDEX environment variable that applies
both to the GBM and EGLDevice backends. When set to a value between 0 and
the number of planes on the connector - 1, the chosen overlay plane will
be used for output, meaning there will be a drmModeSetPlane to configure,
and, in case of EGLDevice, the plane's corresponding EGL layer will get
chosen instead of the CRTC's.

Task-number: QTBUG-57386
Change-Id: I12c89472ea5730987052f39211fadc597d1302ef
Reviewed-by: Pasi Petäjäjärvi <pasi.petajajarvi@qt.io>
This commit is contained in:
Laszlo Agocs 2016-12-02 10:39:35 +01:00
parent 8d0854c2bd
commit f30b888465
5 changed files with 89 additions and 28 deletions

View File

@ -181,24 +181,41 @@ void QEglFSKmsGbmScreen::flip()
FrameBuffer *fb = framebufferForBufferObject(m_gbm_bo_next);
if (!output().mode_set) {
int ret = drmModeSetCrtc(device()->fd(),
output().crtc_id,
QEglFSKmsOutput &op(output());
const int fd = device()->fd();
const uint32_t w = op.modes[op.mode].hdisplay;
const uint32_t h = op.modes[op.mode].vdisplay;
if (!op.mode_set) {
int ret = drmModeSetCrtc(fd,
op.crtc_id,
fb->fb,
0, 0,
&output().connector_id, 1,
&output().modes[output().mode]);
&op.connector_id, 1,
&op.modes[op.mode]);
if (ret) {
qErrnoWarning("Could not set DRM mode!");
if (ret == -1) {
qErrnoWarning(errno, "Could not set DRM mode!");
} else {
output().mode_set = true;
op.mode_set = true;
setPowerState(PowerStateOn);
if (!op.plane_set) {
op.plane_set = true;
if (op.wants_plane) {
int ret = drmModeSetPlane(fd, op.plane_id, op.crtc_id,
uint32_t(-1), 0,
0, 0, w, h,
0 << 16, 0 << 16, w << 16, h << 16);
if (ret == -1)
qErrnoWarning(errno, "drmModeSetPlane failed");
}
}
}
}
int ret = drmModePageFlip(device()->fd(),
output().crtc_id,
int ret = drmModePageFlip(fd,
op.crtc_id,
fb->fb,
DRM_MODE_PAGE_FLIP_EVENT,
this);

View File

@ -39,11 +39,11 @@
****************************************************************************/
#include "qeglfskmsegldeviceintegration.h"
#include "qeglfskmsegldevice.h"
#include "qeglfskmsegldevicescreen.h"
#include <QtEglSupport/private/qeglconvenience_p.h>
#include "private/qeglfswindow_p.h"
#include "private/qeglfscursor_p.h"
#include "qeglfskmsegldevice.h"
#include "qeglfskmsscreen.h"
#include <QLoggingCategory>
#include <private/qmath_p.h>
@ -171,20 +171,23 @@ void QEglJetsonTK1Window::resetSurface()
return;
}
QEglFSKmsScreen *cur_screen = static_cast<QEglFSKmsScreen*>(screen());
QEglFSKmsEglDeviceScreen *cur_screen = static_cast<QEglFSKmsEglDeviceScreen *>(screen());
Q_ASSERT(cur_screen);
qCDebug(qLcEglfsKmsDebug, "Searching for id: %d", cur_screen->output().crtc_id);
QEglFSKmsOutput &output(cur_screen->output());
const uint32_t wantedId = !output.wants_plane ? output.crtc_id : output.plane_id;
qCDebug(qLcEglfsKmsDebug, "Searching for id: %d", wantedId);
EGLOutputLayerEXT layer = EGL_NO_OUTPUT_LAYER_EXT;
for (int i = 0; i < actualCount; ++i) {
EGLAttrib id;
if (m_integration->m_funcs->query_output_layer_attrib(display, layers[i], EGL_DRM_CRTC_EXT, &id)) {
qCDebug(qLcEglfsKmsDebug, " [%d] layer %p - crtc %d", i, layers[i], (int) id);
if (id == EGLAttrib(cur_screen->output().crtc_id))
if (id == EGLAttrib(wantedId))
layer = layers[i];
} else if (m_integration->m_funcs->query_output_layer_attrib(display, layers[i], EGL_DRM_PLANE_EXT, &id)) {
// Not used yet, just for debugging.
qCDebug(qLcEglfsKmsDebug, " [%d] layer %p - plane %d", i, layers[i], (int) id);
if (id == EGLAttrib(wantedId))
layer = layers[i];
} else {
qCDebug(qLcEglfsKmsDebug, " [%d] layer %p - unknown", i, layers[i]);
}

View File

@ -67,13 +67,16 @@ QPlatformCursor *QEglFSKmsEglDeviceScreen::cursor() const
void QEglFSKmsEglDeviceScreen::waitForFlip()
{
if (!output().mode_set) {
output().mode_set = true;
QEglFSKmsOutput &op(output());
const int fd = device()->fd();
const uint32_t w = op.modes[op.mode].hdisplay;
const uint32_t h = op.modes[op.mode].vdisplay;
drmModeCrtcPtr currentMode = drmModeGetCrtc(device()->fd(), output().crtc_id);
const bool alreadySet = currentMode
&& currentMode->width == output().modes[output().mode].hdisplay
&& currentMode->height == output().modes[output().mode].vdisplay;
if (!op.mode_set) {
op.mode_set = true;
drmModeCrtcPtr currentMode = drmModeGetCrtc(fd, op.crtc_id);
const bool alreadySet = currentMode && currentMode->width == w && currentMode->height == h;
if (currentMode)
drmModeFreeCrtc(currentMode);
if (alreadySet) {
@ -87,14 +90,26 @@ void QEglFSKmsEglDeviceScreen::waitForFlip()
}
qCDebug(qLcEglfsKmsDebug, "Setting mode");
int ret = drmModeSetCrtc(device()->fd(), output().crtc_id,
int ret = drmModeSetCrtc(fd, op.crtc_id,
uint32_t(-1), 0, 0,
&output().connector_id, 1,
&output().modes[output().mode]);
&op.connector_id, 1,
&op.modes[op.mode]);
if (ret)
qFatal("drmModeSetCrtc failed");
qErrnoWarning(errno, "drmModeSetCrtc failed");
}
if (!op.plane_set) {
op.plane_set = true;
if (op.wants_plane) {
qCDebug(qLcEglfsKmsDebug, "Setting plane %u", op.plane_id);
int ret = drmModeSetPlane(fd, op.plane_id, op.crtc_id, uint32_t(-1), 0,
0, 0, w, h,
0 << 16, 0 << 16, w << 16, h << 16);
if (ret == -1)
qErrnoWarning(errno, "drmModeSetPlane failed");
}
}
}
QT_END_NAMESPACE

View File

@ -329,9 +329,32 @@ QEglFSKmsScreen *QEglFSKmsDevice::createScreenForConnector(drmModeResPtr resourc
drmModeGetCrtc(m_dri_fd, crtc_id),
modes,
connector->subpixel,
connectorProperty(connector, QByteArrayLiteral("DPMS"))
connectorProperty(connector, QByteArrayLiteral("DPMS")),
false,
0,
false
};
bool ok;
int idx = qEnvironmentVariableIntValue("QT_QPA_EGLFS_KMS_PLANE_INDEX", &ok);
if (ok) {
drmModePlaneRes *planeResources = drmModeGetPlaneResources(m_dri_fd);
if (planeResources) {
if (idx >= 0 && idx < int(planeResources->count_planes)) {
drmModePlane *plane = drmModeGetPlane(m_dri_fd, planeResources->planes[idx]);
if (plane) {
output.wants_plane = true;
output.plane_id = plane->plane_id;
qCDebug(qLcEglfsKmsDebug, "Forcing plane index %d, plane id %u (belongs to crtc id %u)",
idx, plane->plane_id, plane->crtc_id);
drmModeFreePlane(plane);
}
} else {
qWarning("Invalid plane index %d, must be between 0 and %u", idx, planeResources->count_planes - 1);
}
}
}
m_crtc_allocator |= (1 << output.crtc_id);
m_connector_allocator |= (1 << output.connector_id);
@ -406,7 +429,7 @@ void QEglFSKmsDevice::createScreens()
if (idx >= 0 && idx < resources->count_connectors)
wantedConnectorIndex = idx;
else
qWarning("Invalid connector index %d", idx);
qWarning("Invalid connector index %d, must be between 0 and %u", idx, resources->count_connectors - 1);
}
for (int i = 0; i < resources->count_connectors; i++) {

View File

@ -67,6 +67,9 @@ struct QEglFSKmsOutput
QList<drmModeModeInfo> modes;
int subpixel;
drmModePropertyPtr dpms_prop;
bool wants_plane;
uint32_t plane_id;
bool plane_set;
};
class Q_EGLFS_EXPORT QEglFSKmsScreen : public QEglFSScreen