14#include <QLoggingCategory>
15#include <QGuiApplication>
17#include <QtFbSupport/private/qfbcursor_p.h>
18#include <QtFbSupport/private/qfbwindow_p.h>
19#include <QtKmsSupport/private/qkmsdevice_p.h>
20#include <QtCore/private/qcore_unix_p.h>
50 const drmModeModeInfo &modeInfo(kmsOutput.modes[kmsOutput.mode]);
51 return QSize(modeInfo.hdisplay, modeInfo.vdisplay);
74 const QPoint &virtualPos,
75 const QList<QPlatformScreen *> &virtualSiblings)
override;
77 bool createFramebuffer(
Output *output,
int bufferIdx);
78 void destroyFramebuffer(
Output *output,
int bufferIdx);
80 static void pageFlipHandler(
int fd,
unsigned int sequence,
81 unsigned int tv_sec,
unsigned int tv_usec,
void *user_data);
83 QList<Output> m_outputs;
88 const QString path = screenConfig->devicePath();
89 return path.isEmpty() ? QStringLiteral(
"/dev/dri/card0") : path;
99 int fd = qt_safe_open(devicePath().toLocal8Bit().constData(), O_RDWR | O_CLOEXEC);
101 qErrnoWarning(
"Could not open DRM device %s", qPrintable(devicePath()));
105 uint64_t hasDumbBuf = 0;
106 if (drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &hasDumbBuf) == -1 || !hasDumbBuf) {
107 qWarning(
"Dumb buffers not supported");
114 qCDebug(qLcFbDrm,
"DRM device %s opened", qPrintable(devicePath()));
121 for (Output &output : m_outputs)
122 output.kmsOutput.cleanup(
this);
127 qCDebug(qLcFbDrm,
"Closing DRM device");
135 Q_UNREACHABLE_RETURN(
nullptr);
140 qCDebug(qLcFbDrm,
"Got a new output: %s", qPrintable(output.name));
142 o.kmsOutput = output;
149 const QPoint &virtualPos,
150 const QList<QPlatformScreen *> &virtualSiblings)
154 Q_UNUSED(virtualPos);
155 Q_UNUSED(virtualSiblings);
162 case DRM_FORMAT_RGB565:
163 case DRM_FORMAT_BGR565:
173 case DRM_FORMAT_RGB565:
174 case DRM_FORMAT_BGR565:
176 case DRM_FORMAT_XRGB8888:
177 case DRM_FORMAT_XBGR8888:
179 case DRM_FORMAT_XRGB2101010:
180 case DRM_FORMAT_XBGR2101010:
190 case DRM_FORMAT_XRGB8888:
191 case DRM_FORMAT_XBGR8888:
192 return QImage::Format_RGB32;
193 case DRM_FORMAT_ARGB8888:
194 case DRM_FORMAT_ABGR8888:
195 return QImage::Format_ARGB32;
196 case DRM_FORMAT_RGB565:
197 case DRM_FORMAT_BGR565:
198 return QImage::Format_RGB16;
199 case DRM_FORMAT_XRGB2101010:
200 case DRM_FORMAT_XBGR2101010:
201 return QImage::Format_RGB30;
202 case DRM_FORMAT_ARGB2101010:
203 case DRM_FORMAT_ABGR2101010:
204 return QImage::Format_A2RGB30_Premultiplied;
206 return QImage::Format_ARGB32;
212 const QSize size = output->currentRes();
213 const uint32_t w = size.width();
214 const uint32_t h = size.height();
215 const uint32_t bpp = bppForDrmFormat(output->kmsOutput.drm_format);
216 drm_mode_create_dumb creq = {
222 if (drmIoctl(fd(), DRM_IOCTL_MODE_CREATE_DUMB, &creq) == -1) {
223 qErrnoWarning(errno,
"Failed to create dumb buffer");
228 fb.handle = creq.handle;
229 fb.pitch = creq.pitch;
231 qCDebug(qLcFbDrm,
"Got a dumb buffer for size %dx%d and bpp %u: handle %u, pitch %u, size %u",
232 w, h, bpp, fb.handle, fb.pitch, (uint) fb.size);
234 uint32_t handles[4] = { fb.handle };
235 uint32_t strides[4] = { fb.pitch };
236 uint32_t offsets[4] = { 0 };
238 if (drmModeAddFB2(fd(), w, h, output->kmsOutput.drm_format,
239 handles, strides, offsets, &fb.fb, 0) == -1) {
240 qErrnoWarning(errno,
"Failed to add FB");
244 drm_mode_map_dumb mreq = {
248 if (drmIoctl(fd(), DRM_IOCTL_MODE_MAP_DUMB, &mreq) == -1) {
249 qErrnoWarning(errno,
"Failed to map dumb buffer");
252 fb.p = mmap(
nullptr, fb.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd(), mreq.offset);
254 qErrnoWarning(errno,
"Failed to mmap dumb buffer");
258 qCDebug(qLcFbDrm,
"FB is %u (DRM format 0x%x), mapped at %p", fb.fb, output->kmsOutput.drm_format, fb
.p);
259 memset(fb
.p, 0, fb.size);
261 fb.wrapper = QImage(
static_cast<uchar *>(fb
.p), w, h, fb.pitch, formatForDrmFormat(output->kmsOutput.drm_format));
268 for (Output &output : m_outputs) {
269 for (
int i = 0; i < BUFFER_COUNT; ++i) {
270 if (!createFramebuffer(&output, i))
274 output.flipped =
false;
282 munmap(fb
.p, fb.size);
284 if (drmModeRmFB(fd(), fb.fb) == -1)
285 qErrnoWarning(
"Failed to remove fb");
288 drm_mode_destroy_dumb dreq = { fb.handle };
289 if (drmIoctl(fd(), DRM_IOCTL_MODE_DESTROY_DUMB, &dreq) == -1)
290 qErrnoWarning(errno,
"Failed to destroy dumb buffer %u", fb.handle);
297 for (Output &output : m_outputs) {
298 for (
int i = 0; i < BUFFER_COUNT; ++i)
299 destroyFramebuffer(&output, i);
305 for (Output &output : m_outputs) {
306 drmModeModeInfo &modeInfo(output.kmsOutput.modes[output.kmsOutput.mode]);
307 if (drmModeSetCrtc(fd(), output.kmsOutput.crtc_id, output.fb[0].fb, 0, 0,
308 &output.kmsOutput.connector_id, 1, &modeInfo) == -1) {
309 qErrnoWarning(errno,
"Failed to set mode");
313 output.kmsOutput.mode_set =
true;
314 output.kmsOutput.setPowerState(
this, QPlatformScreen::PowerStateOn);
318void QLinuxFbDevice::pageFlipHandler(
int fd,
unsigned int sequence,
319 unsigned int tv_sec,
unsigned int tv_usec,
334 if (drmModePageFlip(fd(), output->kmsOutput.crtc_id, fb.fb, DRM_MODE_PAGE_FLIP_EVENT, output) == -1) {
335 qErrnoWarning(errno,
"Page flip failed");
341 drmEventContext drmEvent;
342 memset(&drmEvent, 0,
sizeof(drmEvent));
343 drmEvent.version = 2;
344 drmEvent.vblank_handler =
nullptr;
345 drmEvent.page_flip_handler = pageFlipHandler;
348 drmHandleEvent(fd(), &drmEvent);
353 : m_screenConfig(
nullptr),
366 delete m_screenConfig;
371 m_screenConfig =
new QKmsScreenConfig;
372 m_screenConfig->loadConfig();
378 m_device->createScreens();
380 qWarning(
"linuxfb: No usable DRM output found");
390 mGeometry = QRect(QPoint(0, 0), output->currentRes());
391 mDepth = depthForDrmFormat(output->kmsOutput.drm_format);
392 mFormat = formatForDrmFormat(output->kmsOutput.drm_format);
393 mPhysicalSize = output->kmsOutput.physical_size;
394 qCDebug(qLcFbDrm) << mGeometry << mPhysicalSize << mDepth << mFormat;
396 QFbScreen::initializeCompositor();
398 mCursor =
new QFbCursor(
this);
405 const QRegion dirty = QFbScreen::doRedraw();
412 output->dirty[i] += dirty;
414 if (output->fb[output
->backFb].wrapper.isNull())
417 QPainter pntr(&output->fb[output
->backFb].wrapper);
420 pntr.setCompositionMode(QPainter::CompositionMode_Source);
421 for (
const QRect &rect : std::as_const(output->dirty[output->backFb]))
422 pntr.drawImage(rect, mScreenImage, rect);
425 output->dirty[output
->backFb] = QRegion();
445#include "moc_qlinuxfbdrmscreen.cpp"
QPlatformScreen * createScreen(const QKmsOutput &output) override
QLinuxFbDevice(QKmsScreenConfig *screenConfig)
void * nativeDisplay() const override
void destroyFramebuffers()
void createFramebuffers()
void swapBuffers(Output *output)
void registerScreen(QPlatformScreen *screen, bool isPrimary, const QPoint &virtualPos, const QList< QPlatformScreen * > &virtualSiblings) override
bool initialize() override
QPixmap grabWindow(WId wid, int x, int y, int width, int height) const override
This function is called when Qt needs to be able to grab the content of a window.
QRegion doRedraw() override
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
static uint32_t bppForDrmFormat(uint32_t drmFormat)
static QString drmDevicePath(QKmsScreenConfig *screenConfig)
static QT_BEGIN_NAMESPACE const int BUFFER_COUNT
static QImage::Format formatForDrmFormat(uint32_t drmFormat)
static int depthForDrmFormat(uint32_t drmFormat)
QRegion dirty[BUFFER_COUNT]
Framebuffer fb[BUFFER_COUNT]