13#include <QLoggingCategory>
14#include <QGuiApplication>
16#include <QtFbSupport/private/qfbcursor_p.h>
17#include <QtFbSupport/private/qfbwindow_p.h>
18#include <QtKmsSupport/private/qkmsdevice_p.h>
19#include <QtCore/private/qcore_unix_p.h>
49 const drmModeModeInfo &modeInfo(kmsOutput.modes[kmsOutput.mode]);
50 return QSize(modeInfo.hdisplay, modeInfo.vdisplay);
73 const QPoint &virtualPos,
74 const QList<QPlatformScreen *> &virtualSiblings)
override;
76 bool createFramebuffer(
Output *output,
int bufferIdx);
77 void destroyFramebuffer(
Output *output,
int bufferIdx);
79 static void pageFlipHandler(
int fd,
unsigned int sequence,
80 unsigned int tv_sec,
unsigned int tv_usec,
void *user_data);
82 QList<Output> m_outputs;
92 int fd = qt_safe_open(devicePath().toLocal8Bit().constData(), O_RDWR | O_CLOEXEC);
94 qErrnoWarning(
"Could not open DRM device %s", qPrintable(devicePath()));
98 uint64_t hasDumbBuf = 0;
99 if (drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &hasDumbBuf) == -1 || !hasDumbBuf) {
100 qWarning(
"Dumb buffers not supported");
107 qCDebug(qLcFbDrm,
"DRM device %s opened", qPrintable(devicePath()));
114 for (Output &output : m_outputs)
115 output.kmsOutput.cleanup(
this);
120 qCDebug(qLcFbDrm,
"Closing DRM device");
128 Q_UNREACHABLE_RETURN(
nullptr);
133 qCDebug(qLcFbDrm,
"Got a new output: %s", qPrintable(output.name));
135 o.kmsOutput = output;
142 const QPoint &virtualPos,
143 const QList<QPlatformScreen *> &virtualSiblings)
147 Q_UNUSED(virtualPos);
148 Q_UNUSED(virtualSiblings);
155 case DRM_FORMAT_RGB565:
156 case DRM_FORMAT_BGR565:
166 case DRM_FORMAT_RGB565:
167 case DRM_FORMAT_BGR565:
169 case DRM_FORMAT_XRGB8888:
170 case DRM_FORMAT_XBGR8888:
172 case DRM_FORMAT_XRGB2101010:
173 case DRM_FORMAT_XBGR2101010:
183 case DRM_FORMAT_XRGB8888:
184 case DRM_FORMAT_XBGR8888:
185 return QImage::Format_RGB32;
186 case DRM_FORMAT_ARGB8888:
187 case DRM_FORMAT_ABGR8888:
188 return QImage::Format_ARGB32;
189 case DRM_FORMAT_RGB565:
190 case DRM_FORMAT_BGR565:
191 return QImage::Format_RGB16;
192 case DRM_FORMAT_XRGB2101010:
193 case DRM_FORMAT_XBGR2101010:
194 return QImage::Format_RGB30;
195 case DRM_FORMAT_ARGB2101010:
196 case DRM_FORMAT_ABGR2101010:
197 return QImage::Format_A2RGB30_Premultiplied;
199 return QImage::Format_ARGB32;
205 const QSize size = output->currentRes();
206 const uint32_t w = size.width();
207 const uint32_t h = size.height();
208 const uint32_t bpp = bppForDrmFormat(output->kmsOutput.drm_format);
209 drm_mode_create_dumb creq = {
215 if (drmIoctl(fd(), DRM_IOCTL_MODE_CREATE_DUMB, &creq) == -1) {
216 qErrnoWarning(errno,
"Failed to create dumb buffer");
221 fb.handle = creq.handle;
222 fb.pitch = creq.pitch;
224 qCDebug(qLcFbDrm,
"Got a dumb buffer for size %dx%d and bpp %u: handle %u, pitch %u, size %u",
225 w, h, bpp, fb.handle, fb.pitch, (uint) fb.size);
227 uint32_t handles[4] = { fb.handle };
228 uint32_t strides[4] = { fb.pitch };
229 uint32_t offsets[4] = { 0 };
231 if (drmModeAddFB2(fd(), w, h, output->kmsOutput.drm_format,
232 handles, strides, offsets, &fb.fb, 0) == -1) {
233 qErrnoWarning(errno,
"Failed to add FB");
237 drm_mode_map_dumb mreq = {
241 if (drmIoctl(fd(), DRM_IOCTL_MODE_MAP_DUMB, &mreq) == -1) {
242 qErrnoWarning(errno,
"Failed to map dumb buffer");
245 fb.p = mmap(
nullptr, fb.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd(), mreq.offset);
247 qErrnoWarning(errno,
"Failed to mmap dumb buffer");
251 qCDebug(qLcFbDrm,
"FB is %u (DRM format 0x%x), mapped at %p", fb.fb, output->kmsOutput.drm_format, fb.p);
252 memset(fb
.p, 0, fb.size);
254 fb.wrapper = QImage(
static_cast<uchar *>(fb.p), w, h, fb.pitch, formatForDrmFormat(output->kmsOutput.drm_format));
261 for (Output &output : m_outputs) {
262 for (
int i = 0; i < BUFFER_COUNT; ++i) {
263 if (!createFramebuffer(&output, i))
267 output.flipped =
false;
275 munmap(fb
.p, fb.size);
277 if (drmModeRmFB(fd(), fb.fb) == -1)
278 qErrnoWarning(
"Failed to remove fb");
281 drm_mode_destroy_dumb dreq = { fb.handle };
282 if (drmIoctl(fd(), DRM_IOCTL_MODE_DESTROY_DUMB, &dreq) == -1)
283 qErrnoWarning(errno,
"Failed to destroy dumb buffer %u", fb.handle);
290 for (Output &output : m_outputs) {
291 for (
int i = 0; i < BUFFER_COUNT; ++i)
292 destroyFramebuffer(&output, i);
298 for (Output &output : m_outputs) {
299 drmModeModeInfo &modeInfo(output.kmsOutput.modes[output.kmsOutput.mode]);
300 if (drmModeSetCrtc(fd(), output.kmsOutput.crtc_id, output.fb[0].fb, 0, 0,
301 &output.kmsOutput.connector_id, 1, &modeInfo) == -1) {
302 qErrnoWarning(errno,
"Failed to set mode");
306 output.kmsOutput.mode_set =
true;
307 output.kmsOutput.setPowerState(
this, QPlatformScreen::PowerStateOn);
311void QLinuxFbDevice::pageFlipHandler(
int fd,
unsigned int sequence,
312 unsigned int tv_sec,
unsigned int tv_usec,
327 if (drmModePageFlip(fd(), output->kmsOutput.crtc_id, fb.fb, DRM_MODE_PAGE_FLIP_EVENT, output) == -1) {
328 qErrnoWarning(errno,
"Page flip failed");
334 drmEventContext drmEvent;
335 memset(&drmEvent, 0,
sizeof(drmEvent));
336 drmEvent.version = 2;
337 drmEvent.vblank_handler =
nullptr;
338 drmEvent.page_flip_handler = pageFlipHandler;
341 drmHandleEvent(fd(), &drmEvent);
346 : m_screenConfig(
nullptr),
359 delete m_screenConfig;
364 m_screenConfig =
new QKmsScreenConfig;
365 m_screenConfig->loadConfig();
371 m_device->createScreens();
379 mGeometry = QRect(QPoint(0, 0), output->currentRes());
380 mDepth = depthForDrmFormat(output->kmsOutput.drm_format);
381 mFormat = formatForDrmFormat(output->kmsOutput.drm_format);
382 mPhysicalSize = output->kmsOutput.physical_size;
383 qCDebug(qLcFbDrm) << mGeometry << mPhysicalSize << mDepth << mFormat;
385 QFbScreen::initializeCompositor();
387 mCursor =
new QFbCursor(
this);
394 const QRegion dirty = QFbScreen::doRedraw();
401 output->dirty[i] += dirty;
403 if (output->fb[output
->backFb].wrapper.isNull())
406 QPainter pntr(&output->fb[output
->backFb].wrapper);
409 pntr.setCompositionMode(QPainter::CompositionMode_Source);
410 for (
const QRect &rect : std::as_const(output->dirty[output->backFb]))
411 pntr.drawImage(rect, mScreenImage, rect);
414 output->dirty[output
->backFb] = QRegion();
434#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]