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;
93 int fd = qt_safe_open(devicePath().toLocal8Bit().constData(), O_RDWR | O_CLOEXEC);
95 qErrnoWarning(
"Could not open DRM device %s", qPrintable(devicePath()));
99 uint64_t hasDumbBuf = 0;
100 if (drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &hasDumbBuf) == -1 || !hasDumbBuf) {
101 qWarning(
"Dumb buffers not supported");
108 qCDebug(qLcFbDrm,
"DRM device %s opened", qPrintable(devicePath()));
115 for (Output &output : m_outputs)
116 output.kmsOutput.cleanup(
this);
121 qCDebug(qLcFbDrm,
"Closing DRM device");
129 Q_UNREACHABLE_RETURN(
nullptr);
134 qCDebug(qLcFbDrm,
"Got a new output: %s", qPrintable(output.name));
136 o.kmsOutput = output;
143 const QPoint &virtualPos,
144 const QList<QPlatformScreen *> &virtualSiblings)
148 Q_UNUSED(virtualPos);
149 Q_UNUSED(virtualSiblings);
156 case DRM_FORMAT_RGB565:
157 case DRM_FORMAT_BGR565:
167 case DRM_FORMAT_RGB565:
168 case DRM_FORMAT_BGR565:
170 case DRM_FORMAT_XRGB8888:
171 case DRM_FORMAT_XBGR8888:
173 case DRM_FORMAT_XRGB2101010:
174 case DRM_FORMAT_XBGR2101010:
184 case DRM_FORMAT_XRGB8888:
185 case DRM_FORMAT_XBGR8888:
186 return QImage::Format_RGB32;
187 case DRM_FORMAT_ARGB8888:
188 case DRM_FORMAT_ABGR8888:
189 return QImage::Format_ARGB32;
190 case DRM_FORMAT_RGB565:
191 case DRM_FORMAT_BGR565:
192 return QImage::Format_RGB16;
193 case DRM_FORMAT_XRGB2101010:
194 case DRM_FORMAT_XBGR2101010:
195 return QImage::Format_RGB30;
196 case DRM_FORMAT_ARGB2101010:
197 case DRM_FORMAT_ABGR2101010:
198 return QImage::Format_A2RGB30_Premultiplied;
200 return QImage::Format_ARGB32;
206 const QSize size = output->currentRes();
207 const uint32_t w = size.width();
208 const uint32_t h = size.height();
209 const uint32_t bpp = bppForDrmFormat(output->kmsOutput.drm_format);
210 drm_mode_create_dumb creq = {
216 if (drmIoctl(fd(), DRM_IOCTL_MODE_CREATE_DUMB, &creq) == -1) {
217 qErrnoWarning(errno,
"Failed to create dumb buffer");
222 fb.handle = creq.handle;
223 fb.pitch = creq.pitch;
225 qCDebug(qLcFbDrm,
"Got a dumb buffer for size %dx%d and bpp %u: handle %u, pitch %u, size %u",
226 w, h, bpp, fb.handle, fb.pitch, (uint) fb.size);
228 uint32_t handles[4] = { fb.handle };
229 uint32_t strides[4] = { fb.pitch };
230 uint32_t offsets[4] = { 0 };
232 if (drmModeAddFB2(fd(), w, h, output->kmsOutput.drm_format,
233 handles, strides, offsets, &fb.fb, 0) == -1) {
234 qErrnoWarning(errno,
"Failed to add FB");
238 drm_mode_map_dumb mreq = {
242 if (drmIoctl(fd(), DRM_IOCTL_MODE_MAP_DUMB, &mreq) == -1) {
243 qErrnoWarning(errno,
"Failed to map dumb buffer");
246 fb.p = mmap(
nullptr, fb.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd(), mreq.offset);
248 qErrnoWarning(errno,
"Failed to mmap dumb buffer");
252 qCDebug(qLcFbDrm,
"FB is %u (DRM format 0x%x), mapped at %p", fb.fb, output->kmsOutput.drm_format, fb
.p);
253 memset(fb
.p, 0, fb.size);
255 fb.wrapper = QImage(
static_cast<uchar *>(fb
.p), w, h, fb.pitch, formatForDrmFormat(output->kmsOutput.drm_format));
262 for (Output &output : m_outputs) {
263 for (
int i = 0; i < BUFFER_COUNT; ++i) {
264 if (!createFramebuffer(&output, i))
268 output.flipped =
false;
276 munmap(fb
.p, fb.size);
278 if (drmModeRmFB(fd(), fb.fb) == -1)
279 qErrnoWarning(
"Failed to remove fb");
282 drm_mode_destroy_dumb dreq = { fb.handle };
283 if (drmIoctl(fd(), DRM_IOCTL_MODE_DESTROY_DUMB, &dreq) == -1)
284 qErrnoWarning(errno,
"Failed to destroy dumb buffer %u", fb.handle);
291 for (Output &output : m_outputs) {
292 for (
int i = 0; i < BUFFER_COUNT; ++i)
293 destroyFramebuffer(&output, i);
299 for (Output &output : m_outputs) {
300 drmModeModeInfo &modeInfo(output.kmsOutput.modes[output.kmsOutput.mode]);
301 if (drmModeSetCrtc(fd(), output.kmsOutput.crtc_id, output.fb[0].fb, 0, 0,
302 &output.kmsOutput.connector_id, 1, &modeInfo) == -1) {
303 qErrnoWarning(errno,
"Failed to set mode");
307 output.kmsOutput.mode_set =
true;
308 output.kmsOutput.setPowerState(
this, QPlatformScreen::PowerStateOn);
312void QLinuxFbDevice::pageFlipHandler(
int fd,
unsigned int sequence,
313 unsigned int tv_sec,
unsigned int tv_usec,
328 if (drmModePageFlip(fd(), output->kmsOutput.crtc_id, fb.fb, DRM_MODE_PAGE_FLIP_EVENT, output) == -1) {
329 qErrnoWarning(errno,
"Page flip failed");
335 drmEventContext drmEvent;
336 memset(&drmEvent, 0,
sizeof(drmEvent));
337 drmEvent.version = 2;
338 drmEvent.vblank_handler =
nullptr;
339 drmEvent.page_flip_handler = pageFlipHandler;
342 drmHandleEvent(fd(), &drmEvent);
347 : m_screenConfig(
nullptr),
360 delete m_screenConfig;
365 m_screenConfig =
new QKmsScreenConfig;
366 m_screenConfig->loadConfig();
372 m_device->createScreens();
380 mGeometry = QRect(QPoint(0, 0), output->currentRes());
381 mDepth = depthForDrmFormat(output->kmsOutput.drm_format);
382 mFormat = formatForDrmFormat(output->kmsOutput.drm_format);
383 mPhysicalSize = output->kmsOutput.physical_size;
384 qCDebug(qLcFbDrm) << mGeometry << mPhysicalSize << mDepth << mFormat;
386 QFbScreen::initializeCompositor();
388 mCursor =
new QFbCursor(
this);
395 const QRegion dirty = QFbScreen::doRedraw();
402 output->dirty[i] += dirty;
404 if (output->fb[output
->backFb].wrapper.isNull())
407 QPainter pntr(&output->fb[output
->backFb].wrapper);
410 pntr.setCompositionMode(QPainter::CompositionMode_Source);
411 for (
const QRect &rect : std::as_const(output->dirty[output->backFb]))
412 pntr.drawImage(rect, mScreenImage, rect);
415 output->dirty[output
->backFb] = QRegion();
435#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 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]