KWin
Loading...
Searching...
No Matches
mock_drm.cpp
Go to the documentation of this file.
1/*
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5 SPDX-FileCopyrightText: 2022 Xaver Hugl <xaver.hugl@gmail.com>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9#include "mock_drm.h"
10
11#include <errno.h>
12extern "C" {
13#include <libxcvt/libxcvt.h>
14}
15#include <math.h>
16
17#include <memory>
18
19#include <QMap>
20#include <QDebug>
21
22// Mock impls
23
24static QMap<int, MockGpu*> s_gpus;
25
26static MockGpu *getGpu(int fd)
27{
28 return s_gpus[fd];
29}
30
31MockGpu::MockGpu(int fd, const QString &devNode, int numCrtcs, int gammaSize)
32 : fd(fd)
33 , devNode(devNode)
34{
35 s_gpus.insert(fd, this);
36 for (int i = 0; i < numCrtcs; i++) {
37 const auto &plane = std::make_shared<MockPlane>(this, PlaneType::Primary, i);
39 planes << plane;
40 }
46}
47
49{
50 s_gpus.remove(fd);
51}
52
54{
55 auto it = std::find_if(propertyBlobs.begin(), propertyBlobs.end(), [id](const auto &propBlob) {
56 return propBlob->id == id;
57 });
58 return it == propertyBlobs.end() ? nullptr : it->get();
59}
60
62{
63 auto it = std::find_if(connectors.constBegin(), connectors.constEnd(), [id](const auto &c){return c->id == id;});
64 return it == connectors.constEnd() ? nullptr : (*it).get();
65}
66
67MockCrtc *MockGpu::findCrtc(uint32_t id) const
68{
69 auto it = std::find_if(crtcs.constBegin(), crtcs.constEnd(), [id](const auto &c){return c->id == id;});
70 return it == crtcs.constEnd() ? nullptr : (*it).get();
71}
72
73MockPlane *MockGpu::findPlane(uint32_t id) const
74{
75 auto it = std::find_if(planes.constBegin(), planes.constEnd(), [id](const auto &p){return p->id == id;});
76 return it == planes.constEnd() ? nullptr : (*it).get();
77}
78
79void MockGpu::flipPage(uint32_t crtcId)
80{
81 auto crtc = findCrtc(crtcId);
82 Q_ASSERT(crtc);
83 for (const auto &plane : std::as_const(planes)) {
84 if (plane->getProp(QStringLiteral("CRTC_ID")) == crtc->id) {
85 plane->currentFb = plane->nextFb;
86 }
87 }
88 // TODO page flip event?
89}
90
91//
92
94 : id(gpu->idCounter++)
95 , gpu(gpu)
96{
97 gpu->objects << this;
98}
99
101{
102 gpu->objects.removeOne(this);
103}
104
105uint64_t MockObject::getProp(const QString &propName) const
106{
107 for (const auto &prop : std::as_const(props)) {
108 if (prop.name == propName) {
109 return prop.value;
110 }
111 }
112 Q_UNREACHABLE();
113}
114
115void MockObject::setProp(const QString &propName, uint64_t value)
116{
117 for (auto &prop : props) {
118 if (prop.name == propName) {
119 prop.value = value;
120 return;
121 }
122 }
123 Q_UNREACHABLE();
124}
125
126uint32_t MockObject::getPropId(const QString &propName) const
127{
128 for (const auto &prop : std::as_const(props)) {
129 if (prop.name == propName) {
130 return prop.id;
131 }
132 }
133 Q_UNREACHABLE();
134}
135
136//
137
138MockProperty::MockProperty(MockObject *obj, QString name, uint64_t initialValue, uint32_t flags, QList<QByteArray> enums)
139 : obj(obj)
140 , id(obj->gpu->idCounter++)
141 , flags(flags)
142 , name(name)
143 , value(initialValue)
144 , enums(enums)
145{
146 qDebug("Added property %s with id %u to object %u", qPrintable(name), id, obj->id);
147}
148
149MockPropertyBlob::MockPropertyBlob(MockGpu *gpu, const void *d, size_t size)
150 : gpu(gpu)
151 , id(gpu->idCounter++)
152 , data(malloc(size))
153 , size(size)
154{
155 memcpy(data, d, size);
156}
157
162
163//
164
165#define addProp(name, value, flags) props << MockProperty(this, QStringLiteral(name), value, flags)
166
168 : MockObject(gpu)
169 , connection(DRM_MODE_CONNECTED)
170 , type(DRM_MODE_CONNECTOR_DisplayPort)
171 , encoder(std::make_shared<MockEncoder>(gpu, 0xFF))
172{
173 gpu->encoders << encoder;
174 addProp("CRTC_ID", 0, DRM_MODE_PROP_ATOMIC);
175
176 addProp("Subpixel", DRM_MODE_SUBPIXEL_UNKNOWN, DRM_MODE_PROP_IMMUTABLE);
177 addProp("non-desktop", nonDesktop, DRM_MODE_PROP_IMMUTABLE);
178 addProp("vrr_capable", 0, DRM_MODE_PROP_IMMUTABLE);
179
180 addProp("DPMS", DRM_MODE_DPMS_OFF, 0);
181 addProp("EDID", 0, DRM_MODE_PROP_BLOB | DRM_MODE_PROP_IMMUTABLE);
182
183 addMode(1920, 1080, 60.0);
184}
185
186void MockConnector::addMode(uint32_t width, uint32_t height, float refreshRate, bool preferred)
187{
188 auto modeInfo = libxcvt_gen_mode_info(width, height, refreshRate, false, false);
189
190 drmModeModeInfo mode{
191 .clock = uint32_t(modeInfo->dot_clock),
192 .hdisplay = uint16_t(modeInfo->hdisplay),
193 .hsync_start = modeInfo->hsync_start,
194 .hsync_end = modeInfo->hsync_end,
195 .htotal = modeInfo->htotal,
196 .hskew = 0,
197 .vdisplay = uint16_t(modeInfo->vdisplay),
198 .vsync_start = modeInfo->vsync_start,
199 .vsync_end = modeInfo->vsync_end,
200 .vtotal = modeInfo->vtotal,
201 .vscan = 1,
202 .vrefresh = uint32_t(modeInfo->vrefresh),
203 .flags = modeInfo->mode_flags,
204 .type = DRM_MODE_TYPE_DRIVER,
205 };
206 if (preferred) {
207 mode.type |= DRM_MODE_TYPE_PREFERRED;
208 }
209 sprintf(mode.name, "%dx%d@%d", width, height, mode.vrefresh);
210
211 modes.push_back(mode);
212 free(modeInfo);
213}
214
215//
216
217MockCrtc::MockCrtc(MockGpu *gpu, const std::shared_ptr<MockPlane> &legacyPlane, int pipeIndex, int gamma_size)
218 : MockObject(gpu)
219 , pipeIndex(pipeIndex)
220 , gamma_size(gamma_size)
221 , legacyPlane(legacyPlane)
222{
223 addProp("MODE_ID", 0, DRM_MODE_PROP_ATOMIC | DRM_MODE_PROP_BLOB);
224 addProp("ACTIVE", 0, DRM_MODE_PROP_ATOMIC);
225 addProp("GAMMA_LUT", 0, DRM_MODE_PROP_ATOMIC | DRM_MODE_PROP_BLOB);
226 addProp("GAMMA_LUT_SIZE", gamma_size, DRM_MODE_PROP_ATOMIC);
227}
228
229
230//
231
232MockPlane::MockPlane(MockGpu *gpu, PlaneType type, int crtcIndex)
233 : MockObject(gpu)
234 , possibleCrtcs(1 << crtcIndex)
235 , type(type)
236{
237 props << MockProperty(this, QStringLiteral("type"), static_cast<uint64_t>(type), DRM_MODE_PROP_IMMUTABLE | DRM_MODE_PROP_ENUM,
238 {QByteArrayLiteral("Primary"), QByteArrayLiteral("Overlay"), QByteArrayLiteral("Cursor")});
239 addProp("FB_ID", 0, DRM_MODE_PROP_ATOMIC);
240 addProp("CRTC_ID", 0, DRM_MODE_PROP_ATOMIC);
241 addProp("CRTC_X", 0, DRM_MODE_PROP_ATOMIC);
242 addProp("CRTC_Y", 0, DRM_MODE_PROP_ATOMIC);
243 addProp("CRTC_W", 0, DRM_MODE_PROP_ATOMIC);
244 addProp("CRTC_H", 0, DRM_MODE_PROP_ATOMIC);
245 addProp("SRC_X", 0, DRM_MODE_PROP_ATOMIC);
246 addProp("SRC_Y", 0, DRM_MODE_PROP_ATOMIC);
247 addProp("SRC_W", 0, DRM_MODE_PROP_ATOMIC);
248 addProp("SRC_H", 0, DRM_MODE_PROP_ATOMIC);
249}
250
251//
252
253MockEncoder::MockEncoder(MockGpu* gpu, uint32_t possible_crtcs)
254 : MockObject(gpu)
255 , possible_crtcs(possible_crtcs)
256{
257}
258
259
260//
261
262MockFb::MockFb(MockGpu *gpu, uint32_t width, uint32_t height)
263 : id(gpu->idCounter++)
264 , width(width)
265 , height(height)
266 , gpu(gpu)
267{
268 gpu->fbs << this;
269}
270
272{
273 gpu->fbs.removeOne(this);
274}
275
276// drm functions
277
278#define GPU(fd, error) \
279 auto gpu = getGpu(fd); \
280 if (!gpu) { \
281 qWarning("invalid fd %d", fd); \
282 errno = EINVAL; \
283 return error; \
284 } \
285 std::scoped_lock lock(gpu->m_mutex);
286
287drmVersionPtr drmGetVersion(int fd)
288{
289 GPU(fd, nullptr);
290 drmVersionPtr ptr = new drmVersion;
291 ptr->name = new char[gpu->name.size() + 1];
292 strcpy(ptr->name, gpu->name.data());
293 return ptr;
294}
295
296void drmFreeVersion(drmVersionPtr ptr)
297{
298 Q_ASSERT(ptr);
299 delete[] ptr->name;
300 delete ptr;
301}
302
303int drmSetClientCap(int fd, uint64_t capability, uint64_t value)
304{
305 GPU(fd, -EINVAL);
306 if (capability == DRM_CLIENT_CAP_ATOMIC) {
307 if (!gpu->deviceCaps[MOCKDRM_DEVICE_CAP_ATOMIC]) {
308 return -(errno = ENOTSUP);
309 }
310 qDebug("Setting DRM_CLIENT_CAP_ATOMIC to %lu", value);
311 }
312 gpu->clientCaps.insert(capability, value);
313 return 0;
314}
315
316int drmGetCap(int fd, uint64_t capability, uint64_t *value)
317{
318 GPU(fd, -EINVAL);
319 if (gpu->deviceCaps.contains(capability)) {
320 *value = gpu->deviceCaps[capability];
321 return 0;
322 }
323 qDebug("Could not find capability %lu", capability);
324 return -(errno = EINVAL);
325}
326
327int drmHandleEvent(int fd, drmEventContextPtr evctx)
328{
329 GPU(fd, -EINVAL);
330 return -(errno = ENOTSUP);
331}
332
333int drmIoctl(int fd, unsigned long request, void *arg)
334{
335 if (request == DRM_IOCTL_PRIME_FD_TO_HANDLE) {
336 GPU(fd, -EINVAL);
337 auto args = static_cast<drm_prime_handle *>(arg);
338 args->handle = 42; // just pass a dummy value so the request doesn't fail
339 return 0;
340 } else if (request == DRM_IOCTL_PRIME_HANDLE_TO_FD) {
341 return -(errno = ENOTSUP);
342 } else if (request == DRM_IOCTL_GEM_CLOSE) {
343 GPU(fd, -EINVAL);
344 return 0;
345 } else if (request == DRM_IOCTL_MODE_ATOMIC) {
346 const auto args = static_cast<drm_mode_atomic *>(arg);
347 auto req = drmModeAtomicAlloc();
348 const uint32_t *const objects = reinterpret_cast<const uint32_t *>(args->objs_ptr);
349 const uint32_t *const propsCounts = reinterpret_cast<const uint32_t *>(args->count_props_ptr);
350 const uint32_t *const props = reinterpret_cast<const uint32_t *>(args->props_ptr);
351 const uint64_t *const values = reinterpret_cast<const uint64_t *>(args->prop_values_ptr);
352 uint32_t propIndex = 0;
353 for (uint32_t objIndex = 0; objIndex < args->count_objs; objIndex++) {
354 const uint32_t objectId = objects[objIndex];
355 const uint32_t count = propsCounts[objIndex];
356 for (uint32_t i = 0; i < count; i++) {
357 drmModeAtomicAddProperty(req, objectId, props[propIndex + i], values[propIndex + i]);
358 }
359 propIndex += count;
360 }
361 int ret = drmModeAtomicCommit(fd, req, args->flags, reinterpret_cast<void *>(args->user_data));
363 return ret;
364 } else if (request == DRM_IOCTL_MODE_RMFB) {
365 drmModeRmFB(fd, *static_cast<const uint32_t *>(arg));
366 }
367 return -(errno = ENOTSUP);
368}
369
370drmModeResPtr drmModeGetResources(int fd)
371{
372 GPU(fd, nullptr)
373 drmModeResPtr res = new drmModeRes;
374
375 res->count_connectors = gpu->connectors.count();
376 res->connectors = res->count_connectors ? new uint32_t[res->count_connectors] : nullptr;
377 int i = 0;
378 for (const auto &conn : std::as_const(gpu->connectors)) {
379 res->connectors[i++] = conn->id;
380 }
381
382 res->count_encoders = gpu->encoders.count();
383 res->encoders = res->count_encoders ? new uint32_t[res->count_encoders] : nullptr;
384 i = 0;
385 for (const auto &enc : std::as_const(gpu->encoders)) {
386 res->encoders[i++] = enc->id;
387 }
388
389 res->count_crtcs = gpu->crtcs.count();
390 res->crtcs = res->count_crtcs ? new uint32_t[res->count_crtcs] : nullptr;
391 i = 0;
392 for (const auto &crtc : std::as_const(gpu->crtcs)) {
393 res->crtcs[i++] = crtc->id;
394 }
395
396 res->count_fbs = gpu->fbs.count();
397 res->fbs = res->count_fbs ? new uint32_t[res->count_fbs] : nullptr;
398 i = 0;
399 for (const auto &fb : std::as_const(gpu->fbs)) {
400 res->fbs[i++] = fb->id;
401 }
402
403 res->min_width = 0;
404 res->min_height = 0;
405 res->max_width = 2 << 14;
406 res->max_height = 2 << 14;
407
408 gpu->resPtrs << res;
409 return res;
410}
411
412int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth,
413 uint8_t bpp, uint32_t pitch, uint32_t bo_handle,
414 uint32_t *buf_id)
415{
416 GPU(fd, EINVAL)
417 auto fb = new MockFb(gpu, width, height);
418 *buf_id = fb->id;
419 return 0;
420}
421
422int drmModeAddFB2(int fd, uint32_t width, uint32_t height,
423 uint32_t pixel_format, const uint32_t bo_handles[4],
424 const uint32_t pitches[4], const uint32_t offsets[4],
425 uint32_t *buf_id, uint32_t flags)
426{
427 GPU(fd, EINVAL)
428 auto fb = new MockFb(gpu, width, height);
429 *buf_id = fb->id;
430 return 0;
431}
432
433int drmModeAddFB2WithModifiers(int fd, uint32_t width, uint32_t height,
434 uint32_t pixel_format, const uint32_t bo_handles[4],
435 const uint32_t pitches[4], const uint32_t offsets[4],
436 const uint64_t modifier[4], uint32_t *buf_id,
437 uint32_t flags)
438{
439 GPU(fd, EINVAL)
440 if (!gpu->deviceCaps.contains(DRM_CAP_ADDFB2_MODIFIERS)) {
441 return -(errno = ENOTSUP);
442 }
443 auto fb = new MockFb(gpu, width, height);
444 *buf_id = fb->id;
445 return 0;
446}
447
448int drmModeRmFB(int fd, uint32_t bufferId)
449{
450 GPU(fd, EINVAL)
451 auto it = std::find_if(gpu->fbs.begin(), gpu->fbs.end(), [bufferId](const auto &fb){return fb->id == bufferId;});
452 if (it == gpu->fbs.end()) {
453 qWarning("invalid bufferId %u passed to drmModeRmFB", bufferId);
454 return EINVAL;
455 } else {
456 auto fb = *it;
457 gpu->fbs.erase(it);
458 for (const auto &plane : std::as_const(gpu->planes)) {
459 if (plane->nextFb == fb) {
460 plane->nextFb = nullptr;
461 }
462 if (plane->currentFb == fb) {
463 qWarning("current fb %u of plane %u got removed. Deactivating plane", bufferId, plane->id);
464 plane->setProp(QStringLiteral("CRTC_ID"), 0);
465 plane->setProp(QStringLiteral("FB_ID"), 0);
466 plane->currentFb = nullptr;
467
468 auto crtc = gpu->findCrtc(plane->getProp(QStringLiteral("CRTC_ID")));
469 Q_ASSERT(crtc);
470 crtc->setProp(QStringLiteral("ACTIVE"), 0);
471 qWarning("deactvating crtc %u", crtc->id);
472
473 for (const auto &conn : std::as_const(gpu->connectors)) {
474 if (conn->getProp(QStringLiteral("CRTC_ID")) == crtc->id) {
475 conn->setProp(QStringLiteral("CRTC_ID"), 0);
476 qWarning("deactvating connector %u", conn->id);
477 }
478 }
479 }
480 }
481 delete fb;
482 return 0;
483 }
484}
485
486drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId)
487{
488 GPU(fd, nullptr);
489 if (auto crtc = gpu->findCrtc(crtcId)) {
490 drmModeCrtcPtr c = new drmModeCrtc;
491 c->crtc_id = crtcId;
492 c->buffer_id = crtc->currentFb ? crtc->currentFb->id : 0;
493 c->gamma_size = crtc->gamma_size;
494 c->mode_valid = crtc->modeValid;
495 c->mode = crtc->mode;
496 c->x = 0;
497 c->y = 0;
498 c->width = crtc->mode.hdisplay;
499 c->height = crtc->mode.vdisplay;
500 gpu->drmCrtcs << c;
501 return c;
502 } else {
503 qWarning("invalid crtcId %u passed to drmModeGetCrtc", crtcId);
504 errno = EINVAL;
505 return nullptr;
506 }
507}
508
509int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId,
510 uint32_t x, uint32_t y, uint32_t *connectors, int count,
511 drmModeModeInfoPtr mode)
512{
513 GPU(fd, -EINVAL);
514 auto crtc = gpu->findCrtc(crtcId);
515 if (!crtc) {
516 qWarning("invalid crtcId %u passed to drmModeSetCrtc", crtcId);
517 return -(errno = EINVAL);
518 }
519 auto oldModeBlob = crtc->getProp(QStringLiteral("MODE_ID"));
520 uint32_t modeBlob = 0;
521 if (mode) {
522 drmModeCreatePropertyBlob(fd, mode, sizeof(drmModeModeInfo), &modeBlob);
523 }
524
525 auto req = drmModeAtomicAlloc();
526 req->legacyEmulation = true;
527 drmModeAtomicAddProperty(req, crtcId, crtc->getPropId(QStringLiteral("MODE_ID")), modeBlob);
528 drmModeAtomicAddProperty(req, crtcId, crtc->getPropId(QStringLiteral("ACTIVE")), modeBlob && count);
529 QList<uint32_t> conns;
530 for (int i = 0; i < count; i++) {
531 conns << connectors[i];
532 }
533 for (const auto &conn : std::as_const(gpu->connectors)) {
534 if (conns.contains(conn->id)) {
535 drmModeAtomicAddProperty(req, conn->id, conn->getPropId(QStringLiteral("CRTC_ID")), modeBlob ? crtc->id : 0);
536 conns.removeOne(conn->id);
537 } else if (conn->getProp(QStringLiteral("CRTC_ID")) == crtc->id) {
538 drmModeAtomicAddProperty(req, conn->id, conn->getPropId(QStringLiteral("CRTC_ID")), 0);
539 }
540 }
541 if (!conns.isEmpty()) {
542 for (const auto &c : std::as_const(conns)) {
543 qWarning("invalid connector %u passed to drmModeSetCrtc", c);
544 }
546 return -(errno = EINVAL);
547 }
548 drmModeAtomicAddProperty(req, crtc->legacyPlane->id, crtc->legacyPlane->getPropId(QStringLiteral("CRTC_ID")), modeBlob && count ? crtc->id : 0);
549 drmModeAtomicAddProperty(req, crtc->legacyPlane->id, crtc->legacyPlane->getPropId(QStringLiteral("CRTC_X")), x);
550 drmModeAtomicAddProperty(req, crtc->legacyPlane->id, crtc->legacyPlane->getPropId(QStringLiteral("CRTC_Y")), y);
551 drmModeAtomicAddProperty(req, crtc->legacyPlane->id, crtc->legacyPlane->getPropId(QStringLiteral("CRTC_W")), mode->hdisplay - x);
552 drmModeAtomicAddProperty(req, crtc->legacyPlane->id, crtc->legacyPlane->getPropId(QStringLiteral("CRTC_H")), mode->vdisplay - y);
553 drmModeAtomicAddProperty(req, crtc->legacyPlane->id, crtc->legacyPlane->getPropId(QStringLiteral("FB_ID")), bufferId);
554 int result = drmModeAtomicCommit(fd, req, DRM_MODE_ATOMIC_ALLOW_MODESET, nullptr);
556 if (result == 0) {
557 drmModeDestroyPropertyBlob(fd, oldModeBlob);
558 }
559 return result;
560}
561
562int drmModeSetCursor(int fd, uint32_t crtcId, uint32_t bo_handle, uint32_t width, uint32_t height)
563{
564 GPU(fd, -EINVAL);
565 if (auto crtc = gpu->findCrtc(crtcId)) {
566 crtc->cursorRect.setSize(QSize(width, height));
567 return 0;
568 } else {
569 qWarning("invalid crtcId %u passed to drmModeSetCursor", crtcId);
570 return -(errno = EINVAL);
571 }
572}
573
574int drmModeSetCursor2(int fd, uint32_t crtcId, uint32_t bo_handle, uint32_t width, uint32_t height, int32_t hot_x, int32_t hot_y)
575{
576 GPU(fd, -EINVAL);
577 return -(errno = ENOTSUP);
578}
579
580int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y)
581{
582 GPU(fd, -EINVAL);
583 if (auto crtc = gpu->findCrtc(crtcId)) {
584 crtc->cursorRect.moveTo(x, y);
585 return 0;
586 } else {
587 qWarning("invalid crtcId %u passed to drmModeMoveCursor", crtcId);
588 return -(errno = EINVAL);
589 }
590}
591
592drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id)
593{
594 GPU(fd, nullptr);
595 auto it = std::find_if(gpu->encoders.constBegin(), gpu->encoders.constEnd(), [encoder_id](const auto &e){return e->id == encoder_id;});
596 if (it == gpu->encoders.constEnd()) {
597 qWarning("invalid encoder_id %u passed to drmModeGetEncoder", encoder_id);
598 errno = EINVAL;
599 return nullptr;
600 } else {
601 auto encoder = *it;
602 drmModeEncoderPtr enc = new drmModeEncoder;
603 enc->encoder_id = encoder_id;
604 enc->crtc_id = encoder->crtc ? encoder->crtc->id : 0;
605 enc->encoder_type = 0;
606 enc->possible_crtcs = encoder->possible_crtcs;
607 enc->possible_clones = encoder->possible_clones;
608
609 gpu->drmEncoders << enc;
610 return enc;
611 }
612}
613
614// Instance ID of (some) specific connector type, incremented
615// for each new connector (of any type) being created.
616// There are no particular guarantees on the _stability_ of
617// connector type "instance IDs" issued by the kernel,
618// so simply giving each (new) connector a fresh ID is
619// acceptable.
620static std::atomic<int> autoIncrementedConnectorId{};
621
622drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connectorId)
623{
624 GPU(fd, nullptr);
625 if (auto conn = gpu->findConnector(connectorId)) {
626 drmModeConnectorPtr c = new drmModeConnector{};
627 c->connector_id = conn->id;
628 c->connection = conn->connection;
629
630 c->connector_type = conn->type;
631 c->connector_type_id = autoIncrementedConnectorId++;
632
633 c->encoder_id = conn->encoder ? conn->encoder->id : 0;
634 c->count_encoders = conn->encoder ? 1 : 0;
635 c->encoders = c->count_encoders ? new uint32_t[1] : nullptr;
636 if (c->encoders) {
637 c->encoders[0] = conn->encoder->id;
638 }
639 c->count_modes = conn->modes.count();
640 c->modes = c->count_modes ? new drmModeModeInfo[c->count_modes] : nullptr;
641 for (int i = 0; i < c->count_modes; i++) {
642 c->modes[i] = conn->modes[i];
643 }
644 c->mmHeight = 900;
645 c->mmWidth = 1600;
646 c->subpixel = DRM_MODE_SUBPIXEL_HORIZONTAL_RGB;
647
648 // these are not used nor will they be
649 c->count_props = -1;
650 c->props = nullptr;
651 c->prop_values = nullptr;
652
653 gpu->drmConnectors << c;
654 return c;
655 } else {
656 qWarning("invalid connectorId %u passed to drmModeGetConnector", connectorId);
657 errno = EINVAL;
658 return nullptr;
659 }
660}
661
662drmModeConnectorPtr drmModeGetConnectorCurrent(int fd, uint32_t connector_id)
663{
664 return drmModeGetConnector(fd, connector_id);
665}
666
667int drmModeCrtcSetGamma(int fd, uint32_t crtc_id, uint32_t size, uint16_t *red, uint16_t *green, uint16_t *blue)
668{
669 return -(errno = ENOTSUP);
670}
671
672int drmModePageFlip(int fd, uint32_t crtc_id, uint32_t fb_id, uint32_t flags, void *user_data)
673{
674 GPU(fd, -EINVAL);
675 auto crtc = gpu->findCrtc(crtc_id);
676 if (!crtc) {
677 qWarning("invalid crtc_id %u passed to drmModePageFlip", crtc_id);
678 return -(errno = EINVAL);
679 }
680 auto req = drmModeAtomicAlloc();
681 req->legacyEmulation = true;
682 drmModeAtomicAddProperty(req, crtc->legacyPlane->id, crtc->legacyPlane->getPropId(QStringLiteral("FB_ID")), fb_id);
683 int result = drmModeAtomicCommit(fd, req, flags, user_data);
685 return result;
686}
687
688
689drmModePlaneResPtr drmModeGetPlaneResources(int fd)
690{
691 GPU(fd, nullptr);
692 drmModePlaneResPtr res = new drmModePlaneRes;
693 res->count_planes = gpu->planes.count();
694 res->planes = res->count_planes ? new uint32_t[res->count_planes] : nullptr;
695 for (uint i = 0; i < res->count_planes; i++) {
696 res->planes[i] = gpu->planes[i]->id;
697 }
698 gpu->drmPlaneRes << res;
699 return res;
700}
701
702drmModePlanePtr drmModeGetPlane(int fd, uint32_t plane_id)
703{
704 GPU(fd, nullptr);
705 if (auto plane = gpu->findPlane(plane_id)) {
706 drmModePlanePtr p = new drmModePlane;
707 p->plane_id = plane_id;
708 p->crtc_id = plane->getProp(QStringLiteral("CRTC_ID"));
709 p->crtc_x = plane->getProp(QStringLiteral("CRTC_X"));
710 p->crtc_y = plane->getProp(QStringLiteral("CRTC_Y"));
711 p->fb_id = plane->getProp(QStringLiteral("FB_ID"));
712 p->x = plane->getProp(QStringLiteral("SRC_X"));
713 p->y = plane->getProp(QStringLiteral("SRC_Y"));
714 p->possible_crtcs = plane->possibleCrtcs;
715
716 // unused atm:
717 p->count_formats = 0;
718 p->formats = nullptr;
719 p->gamma_size = 0;
720
721 gpu->drmPlanes << p;
722 return p;
723 } else {
724 qWarning("invalid plane_id %u passed to drmModeGetPlane", plane_id);
725 errno = EINVAL;
726 return nullptr;
727 }
728}
729
730drmModePropertyPtr drmModeGetProperty(int fd, uint32_t propertyId)
731{
732 GPU(fd, nullptr);
733 for (const auto &obj : std::as_const(gpu->objects)) {
734 for (auto &prop : std::as_const(obj->props)) {
735 if (prop.id == propertyId) {
736 drmModePropertyPtr p = new drmModePropertyRes;
737 p->prop_id = prop.id;
738 p->flags = prop.flags;
739 auto arr = prop.name.toLocal8Bit();
740 strcpy(p->name, arr.constData());
741
742 p->count_blobs = prop.flags & DRM_MODE_PROP_BLOB ? 1 : 0;
743 if (p->count_blobs) {
744 p->blob_ids = new uint32_t[1];
745 p->blob_ids[0] = prop.value;
746 } else {
747 p->blob_ids = nullptr;
748 }
749
750 p->count_enums = prop.enums.count();
751 p->enums = new drm_mode_property_enum[p->count_enums];
752 for (int i = 0; i < p->count_enums; i++) {
753 strcpy(p->enums[i].name, prop.enums[i].constData());
754 p->enums[i].value = i;
755 }
756
757 p->count_values = 1;
758 p->values = new uint64_t[1];
759 p->values[0] = prop.value;
760
761 gpu->drmProps << p;
762 return p;
763 }
764 }
765 }
766 qWarning("invalid propertyId %u passed to drmModeGetProperty", propertyId);
767 errno = EINVAL;
768 return nullptr;
769}
770
771void drmModeFreeProperty(drmModePropertyPtr ptr)
772{
773 if (!ptr) {
774 return;
775 }
776 for (const auto &gpu : std::as_const(s_gpus)) {
777 if (gpu->drmProps.removeOne(ptr)) {
778 delete[] ptr->values;
779 delete[] ptr->blob_ids;
780 delete[] ptr->enums;
781 delete ptr;
782 return;
783 }
784 }
785}
786
787
788
789drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd, uint32_t blob_id)
790{
791 GPU(fd, nullptr);
792 if (blob_id == 0) {
793 return nullptr;
794 }
795 auto it = std::find_if(gpu->propertyBlobs.begin(), gpu->propertyBlobs.end(), [blob_id](const auto &blob) {
796 return blob->id == blob_id;
797 });
798 if (it == gpu->propertyBlobs.end()) {
799 qWarning("invalid blob_id %u passed to drmModeGetPropertyBlob", blob_id);
800 errno = EINVAL;
801 return nullptr;
802 } else {
803 auto blob = new drmModePropertyBlobRes;
804 blob->id = (*it)->id;
805 blob->length = (*it)->size;
806 blob->data = malloc(blob->length);
807 memcpy(blob->data, (*it)->data, blob->length);
808 return blob;
809 }
810}
811
812void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr)
813{
814 if (!ptr) {
815 return;
816 }
817 for (const auto &gpu : std::as_const(s_gpus)) {
818 if (gpu->drmPropertyBlobs.removeOne(ptr)) {
819 free(ptr->data);
820 delete ptr;
821 return;
822 }
823 }
824}
825
826int drmModeConnectorSetProperty(int fd, uint32_t connector_id, uint32_t property_id, uint64_t value)
827{
828 return drmModeObjectSetProperty(fd, connector_id, DRM_MODE_OBJECT_CONNECTOR, property_id, value);
829}
830
831static uint32_t getType(MockObject *obj)
832{
833 if (dynamic_cast<MockConnector*>(obj)) {
834 return DRM_MODE_OBJECT_CONNECTOR;
835 } else if (dynamic_cast<MockCrtc*>(obj)) {
836 return DRM_MODE_OBJECT_CRTC;
837 } else if (dynamic_cast<MockPlane*>(obj)) {
838 return DRM_MODE_OBJECT_PLANE;
839 } else {
840 return DRM_MODE_OBJECT_ANY;
841 }
842}
843
844drmModeObjectPropertiesPtr drmModeObjectGetProperties(int fd, uint32_t object_id, uint32_t object_type)
845{
846 GPU(fd, nullptr);
847 auto it = std::find_if(gpu->objects.constBegin(), gpu->objects.constEnd(), [object_id](const auto &obj){return obj->id == object_id;});
848 if (it == gpu->objects.constEnd()) {
849 qWarning("invalid object_id %u passed to drmModeObjectGetProperties", object_id);
850 errno = EINVAL;
851 return nullptr;
852 } else {
853 auto obj = *it;
854 if (auto type = getType(obj); type != object_type) {
855 qWarning("wrong object_type %u passed to drmModeObjectGetProperties for object %u with type %u", object_type, object_id, type);
856 errno = EINVAL;
857 return nullptr;
858 }
859 QList<MockProperty> props;
860 bool deviceAtomic = gpu->clientCaps.contains(DRM_CLIENT_CAP_ATOMIC) && gpu->clientCaps[DRM_CLIENT_CAP_ATOMIC];
861 for (const auto &prop : std::as_const(obj->props)) {
862 if (deviceAtomic || !(prop.flags & DRM_MODE_PROP_ATOMIC)) {
863 props << prop;
864 }
865 }
866 drmModeObjectPropertiesPtr p = new drmModeObjectProperties;
867 p->count_props = props.count();
868 p->props = new uint32_t[p->count_props];
869 p->prop_values = new uint64_t[p->count_props];
870 int i = 0;
871 for (const auto &prop : std::as_const(props)) {
872 p->props[i] = prop.id;
873 p->prop_values[i] = prop.value;
874 i++;
875 }
876 gpu->drmObjectProperties << p;
877 return p;
878 }
879}
880
881void drmModeFreeObjectProperties(drmModeObjectPropertiesPtr ptr)
882{
883 for (const auto &gpu : std::as_const(s_gpus)) {
884 if (gpu->drmObjectProperties.removeOne(ptr)) {
885 delete[] ptr->props;
886 delete[] ptr->prop_values;
887 delete ptr;
888 return;
889 }
890 }
891}
892
893int drmModeObjectSetProperty(int fd, uint32_t object_id, uint32_t object_type, uint32_t property_id, uint64_t value)
894{
895 GPU(fd, -EINVAL);
896 auto it = std::find_if(gpu->objects.constBegin(), gpu->objects.constEnd(), [object_id](const auto &obj){return obj->id == object_id;});
897 if (it == gpu->objects.constEnd()) {
898 qWarning("invalid object_id %u passed to drmModeObjectSetProperty", object_id);
899 return -(errno = EINVAL);
900 } else {
901 auto obj = *it;
902 if (auto type = getType(obj); type != object_type) {
903 qWarning("wrong object_type %u passed to drmModeObjectSetProperty for object %u with type %u", object_type, object_id, type);
904 return -(errno = EINVAL);
905 }
906 auto req = drmModeAtomicAlloc();
907 req->legacyEmulation = true;
908 drmModeAtomicAddProperty(req, object_id, property_id, value);
909 int result = drmModeAtomicCommit(fd, req, 0, nullptr);
911 return result;
912 }
913}
914
915static QList<drmModeAtomicReqPtr> s_atomicReqs;
916
917drmModeAtomicReqPtr drmModeAtomicAlloc(void)
918{
919 auto req = new drmModeAtomicReq;
920 s_atomicReqs << req;
921 return req;
922}
923
924void drmModeAtomicFree(drmModeAtomicReqPtr req)
925{
926 s_atomicReqs.removeOne(req);
927 delete req;
928}
929
930int drmModeAtomicAddProperty(drmModeAtomicReqPtr req, uint32_t object_id, uint32_t property_id, uint64_t value)
931{
932 if (!req) {
933 return -(errno = EINVAL);
934 }
935 Prop p;
936 p.obj = object_id;
937 p.prop = property_id;
938 p.value = value;
939 req->props << p;
940 return req->props.count();
941}
942
943static bool checkIfEqual(const drmModeModeInfo &one, const drmModeModeInfo &two)
944{
945 return one.clock == two.clock
946 && one.hdisplay == two.hdisplay
947 && one.hsync_start == two.hsync_start
948 && one.hsync_end == two.hsync_end
949 && one.htotal == two.htotal
950 && one.hskew == two.hskew
951 && one.vdisplay == two.vdisplay
952 && one.vsync_start == two.vsync_start
953 && one.vsync_end == two.vsync_end
954 && one.vtotal == two.vtotal
955 && one.vscan == two.vscan
956 && one.vrefresh == two.vrefresh;
957}
958
959int drmModeAtomicCommit(int fd, drmModeAtomicReqPtr req, uint32_t flags, void *user_data)
960{
961 GPU(fd, -EINVAL);
962 if (!req->legacyEmulation && (!gpu->clientCaps.contains(DRM_CLIENT_CAP_ATOMIC) || !gpu->clientCaps[DRM_CLIENT_CAP_ATOMIC])) {
963 qWarning("drmModeAtomicCommit requires the atomic capability");
964 return -(errno = EINVAL);
965 }
966
967 // verify flags
968 if ((flags & DRM_MODE_ATOMIC_NONBLOCK) && (flags & DRM_MODE_ATOMIC_ALLOW_MODESET)) {
969 qWarning() << "NONBLOCK and MODESET are not allowed together";
970 return -(errno = EINVAL);
971 } else if ((flags & DRM_MODE_ATOMIC_TEST_ONLY) && (flags & DRM_MODE_PAGE_FLIP_EVENT)) {
972 qWarning() << "TEST_ONLY and PAGE_FLIP_EVENT are not allowed together";
973 return -(errno = EINVAL);
974 } else if (flags & DRM_MODE_PAGE_FLIP_ASYNC) {
975 qWarning() << "PAGE_FLIP_ASYNC is currently not supported with AMS";
976 return -(errno = EINVAL);
977 }
978
979 QList<MockConnector> connCopies;
980 for (const auto &conn : std::as_const(gpu->connectors)) {
981 connCopies << *conn;
982 }
983 QList<MockCrtc> crtcCopies;
984 for (const auto &crtc : std::as_const(gpu->crtcs)) {
985 crtcCopies << *crtc;
986 }
987 QList<MockPlane> planeCopies;
988 for (const auto &plane : std::as_const(gpu->planes)) {
989 planeCopies << *plane;
990 }
991
992 QList<MockObject *> objects;
993 for (int i = 0; i < connCopies.count(); i++) {
994 objects << &connCopies[i];
995 }
996 for (int i = 0; i < crtcCopies.count(); i++) {
997 objects << &crtcCopies[i];
998 }
999 for (int i = 0; i < planeCopies.count(); i++) {
1000 objects << &planeCopies[i];
1001 }
1002
1003 // apply changes to the copies
1004 for (int i = 0; i < req->props.count(); i++) {
1005 auto p = req->props[i];
1006 auto it = std::find_if(objects.constBegin(), objects.constEnd(), [p](const auto &obj){return obj->id == p.obj;});
1007 if (it == objects.constEnd()) {
1008 qWarning("Object %u in atomic request not found!", p.obj);
1009 return -(errno = EINVAL);
1010 }
1011 auto &obj = *it;
1012 if (obj->id == p.obj) {
1013 auto prop = std::find_if(obj->props.begin(), obj->props.end(), [p](const auto &prop){return prop.id == p.prop;});
1014 if (prop == obj->props.end()) {
1015 qWarning("Property %u in atomic request for object %u not found!", p.prop, p.obj);
1016 return -(errno = EINVAL);
1017 }
1018 if (prop->value != p.value) {
1019 if (!(flags & DRM_MODE_ATOMIC_ALLOW_MODESET) && (prop->name == QStringLiteral("CRTC_ID") || prop->name == QStringLiteral("ACTIVE"))) {
1020 qWarning("Atomic request without DRM_MODE_ATOMIC_ALLOW_MODESET tries to do a modeset with object %u", obj->id);
1021 return -(errno = EINVAL);
1022 }
1023 if (prop->flags & DRM_MODE_PROP_BLOB) {
1024 auto blobExists = gpu->getBlob(p.value) != nullptr;
1025 if (blobExists != (p.value > 0)) {
1026 qWarning("Atomic request tries to set property %s on obj %u to invalid blob id %lu", qPrintable(prop->name), obj->id, p.value);
1027 return -(errno = EINVAL);
1028 }
1029 }
1030 prop->value = p.value;
1031 }
1032 }
1033 }
1034
1035 // check if the desired changes are allowed
1036 struct Pipeline {
1037 MockCrtc *crtc;
1038 QList<MockConnector *> conns;
1039 MockPlane *primaryPlane = nullptr;
1040 };
1041 QList<Pipeline> pipelines;
1042 for (int i = 0; i < crtcCopies.count(); i++) {
1043 if (crtcCopies[i].getProp(QStringLiteral("ACTIVE"))) {
1044 auto blob = gpu->getBlob(crtcCopies[i].getProp(QStringLiteral("MODE_ID")));
1045 if (!blob) {
1046 qWarning("Atomic request tries to enable CRTC %u without a mode", crtcCopies[i].id);
1047 return -(errno = EINVAL);
1048 } else if (blob->size != sizeof(drmModeModeInfo)) {
1049 qWarning("Atomic request tries to enable CRTC %u with an invalid mode blob", crtcCopies[i].id);
1050 return -(errno = EINVAL);
1051 }
1052 Pipeline pipeline;
1053 pipeline.crtc = &crtcCopies[i];
1054 pipelines << pipeline;
1055 }
1056 }
1057 for (int i = 0; i < connCopies.count(); i++) {
1058 if (auto crtc = connCopies[i].getProp(QStringLiteral("CRTC_ID"))) {
1059 bool found = false;
1060 for (int p = 0; p < pipelines.count(); p++) {
1061 if (pipelines[p].crtc->id == crtc) {
1062 pipelines[p].conns << &connCopies[i];
1063 found = true;
1064 break;
1065 }
1066 }
1067 if (!found) {
1068 qWarning("CRTC_ID of connector %u points to inactive or wrong crtc", connCopies[i].id);
1069 return -(errno = EINVAL);
1070 }
1071 }
1072 }
1073 for (int i = 0; i < planeCopies.count(); i++) {
1074 if (auto crtc = planeCopies[i].getProp(QStringLiteral("CRTC_ID"))) {
1075 bool found = false;
1076 for (int p = 0; p < pipelines.count(); p++) {
1077 if (pipelines[p].crtc->id == crtc) {
1078 if (pipelines[p].primaryPlane) {
1079 qWarning("crtc %u has more than one primary planes assigned: %u and %u", pipelines[p].crtc->id, pipelines[p].primaryPlane->id, planeCopies[i].id);
1080 return -(errno = EINVAL);
1081 } else if (!(planeCopies[i].possibleCrtcs & (1 << pipelines[p].crtc->pipeIndex))) {
1082 qWarning("crtc %u is not suitable for primary plane %u", pipelines[p].crtc->id, planeCopies[i].id);
1083 return -(errno = EINVAL);
1084 } else {
1085 pipelines[p].primaryPlane = &planeCopies[i];
1086 found = true;
1087 break;
1088 }
1089 }
1090 }
1091 if (!found) {
1092 qWarning("CRTC_ID of plane %u points to inactive or wrong crtc", planeCopies[i].id);
1093 return -(errno = EINVAL);
1094 }
1095 auto fbId = planeCopies[i].getProp(QStringLiteral("FB_ID"));
1096 if (!fbId) {
1097 qWarning("FB_ID of active plane %u is 0", planeCopies[i].id);
1098 return -(errno = EINVAL);
1099 }
1100 auto it = std::find_if(gpu->fbs.constBegin(), gpu->fbs.constEnd(), [fbId](auto fb){return fb->id == fbId;});
1101 if (it == gpu->fbs.constEnd()) {
1102 qWarning("FB_ID %lu of active plane %u is invalid", fbId, planeCopies[i].id);
1103 return -(errno = EINVAL);
1104 }
1105 planeCopies[i].nextFb = *it;
1106 } else {
1107 planeCopies[i].nextFb = nullptr;
1108 }
1109 }
1110 for (const auto &p : std::as_const(pipelines)) {
1111 if (p.conns.isEmpty()) {
1112 qWarning("Active crtc %u has no assigned connectors", p.crtc->id);
1113 return -(errno = EINVAL);
1114 } else if (!p.primaryPlane) {
1115 qWarning("Active crtc %u has no assigned primary plane", p.crtc->id);
1116 return -(errno = EINVAL);
1117 } else {
1118 drmModeModeInfo mode = *static_cast<drmModeModeInfo*>(gpu->getBlob(p.crtc->getProp(QStringLiteral("MODE_ID")))->data);
1119 for (const auto &conn : p.conns) {
1120 bool modeFound = std::find_if(conn->modes.constBegin(), conn->modes.constEnd(), [mode](const auto &m){
1121 return checkIfEqual(mode, m);
1122 }) != conn->modes.constEnd();
1123 if (!modeFound) {
1124 qWarning("mode on crtc %u is incompatible with connector %u", p.crtc->id, conn->id);
1125 return -(errno = EINVAL);
1126 }
1127 }
1128 }
1129 }
1130
1131 // if wanted, apply them
1132
1133 if (!(flags & DRM_MODE_ATOMIC_TEST_ONLY)) {
1134 for (auto &conn : std::as_const(gpu->connectors)) {
1135 auto it = std::find_if(connCopies.constBegin(), connCopies.constEnd(), [conn](auto c){return c.id == conn->id;});
1136 if (it == connCopies.constEnd()) {
1137 qCritical("implementation error: can't find connector %u", conn->id);
1138 return -(errno = EINVAL);
1139 }
1140 *conn = *it;
1141 }
1142 for (auto &crtc : std::as_const(gpu->crtcs)) {
1143 auto it = std::find_if(crtcCopies.constBegin(), crtcCopies.constEnd(), [crtc](auto c){return c.id == crtc->id;});
1144 if (it == crtcCopies.constEnd()) {
1145 qCritical("implementation error: can't find crtc %u", crtc->id);
1146 return -(errno = EINVAL);
1147 }
1148 *crtc = *it;
1149 }
1150 for (auto &plane : std::as_const(gpu->planes)) {
1151 auto it = std::find_if(planeCopies.constBegin(), planeCopies.constEnd(), [plane](auto c){return c.id == plane->id;});
1152 if (it == planeCopies.constEnd()) {
1153 qCritical("implementation error: can't find plane %u", plane->id);
1154 return -(errno = EINVAL);
1155 }
1156 *plane = *it;
1157 }
1158
1159 if (flags & DRM_MODE_PAGE_FLIP_EVENT) {
1160 // Unsupported
1161 }
1162 }
1163
1164 return 0;
1165}
1166
1167
1168int drmModeCreatePropertyBlob(int fd, const void *data, size_t size, uint32_t *id)
1169{
1170 GPU(fd, -EINVAL);
1171 if (!data || !size || !id) {
1172 return -(errno = EINVAL);
1173 }
1174 auto blob = std::make_unique<MockPropertyBlob>(gpu, data, size);
1175 *id = blob->id;
1176 gpu->propertyBlobs.push_back(std::move(blob));
1177 return 0;
1178}
1179
1180int drmModeDestroyPropertyBlob(int fd, uint32_t id)
1181{
1182 GPU(fd, -EINVAL);
1183 auto it = std::remove_if(gpu->propertyBlobs.begin(), gpu->propertyBlobs.end(), [id](const auto &blob) {
1184 return blob->id == id;
1185 });
1186 if (it == gpu->propertyBlobs.end()) {
1187 return -(errno = EINVAL);
1188 } else {
1189 gpu->propertyBlobs.erase(it, gpu->propertyBlobs.end());
1190 return 0;
1191 }
1192}
1193
1194int drmModeCreateLease(int fd, const uint32_t *objects, int num_objects, int flags, uint32_t *lessee_id)
1195{
1196 return -(errno = ENOTSUP);
1197}
1198
1199drmModeLesseeListPtr drmModeListLessees(int fd)
1200{
1201 return nullptr;
1202}
1203
1204drmModeObjectListPtr drmModeGetLease(int fd)
1205{
1206 return nullptr;
1207}
1208
1209int drmModeRevokeLease(int fd, uint32_t lessee_id)
1210{
1211 return -(errno = ENOTSUP);
1212}
1213
1214void drmModeFreeResources(drmModeResPtr ptr)
1215{
1216 for (const auto &gpu : std::as_const(s_gpus)) {
1217 if (gpu->resPtrs.removeOne(ptr)) {
1218 delete[] ptr->connectors;
1219 delete[] ptr->crtcs;
1220 delete[] ptr->encoders;
1221 delete[] ptr->fbs;
1222 delete ptr;
1223 }
1224 }
1225}
1226
1227void drmModeFreePlaneResources(drmModePlaneResPtr ptr)
1228{
1229 for (const auto &gpu : std::as_const(s_gpus)) {
1230 if (gpu->drmPlaneRes.removeOne(ptr)) {
1231 delete[] ptr->planes;
1232 delete ptr;
1233 }
1234 }
1235}
1236
1237void drmModeFreeCrtc(drmModeCrtcPtr ptr)
1238{
1239 for (const auto &gpu : std::as_const(s_gpus)) {
1240 if (gpu->drmCrtcs.removeOne(ptr)) {
1241 delete ptr;
1242 return;
1243 }
1244 }
1245 Q_UNREACHABLE();
1246}
1247
1248void drmModeFreeConnector(drmModeConnectorPtr ptr)
1249{
1250 for (const auto &gpu : std::as_const(s_gpus)) {
1251 if (gpu->drmConnectors.removeOne(ptr)) {
1252 delete[] ptr->encoders;
1253 delete[] ptr->props;
1254 delete[] ptr->prop_values;
1255 delete ptr;
1256 return;
1257 }
1258 }
1259 Q_UNREACHABLE();
1260}
1261
1262void drmModeFreeEncoder(drmModeEncoderPtr ptr)
1263{
1264 for (const auto &gpu : std::as_const(s_gpus)) {
1265 if (gpu->drmEncoders.removeOne(ptr)) {
1266 delete ptr;
1267 return;
1268 }
1269 }
1270 Q_UNREACHABLE();
1271}
1272
1273void drmModeFreePlane(drmModePlanePtr ptr)
1274{
1275 for (const auto &gpu : std::as_const(s_gpus)) {
1276 if (gpu->drmPlanes.removeOne(ptr)) {
1277 delete ptr;
1278 return;
1279 }
1280 }
1281 Q_UNREACHABLE();
1282}
std::shared_ptr< MockEncoder > encoder
Definition mock_drm.h:77
MockConnector(MockGpu *gpu, bool nonDesktop=false)
Definition mock_drm.cpp:167
QList< drmModeModeInfo > modes
Definition mock_drm.h:78
void addMode(uint32_t width, uint32_t height, float refreshRate, bool preferred=false)
Definition mock_drm.cpp:186
int gamma_size
Definition mock_drm.h:99
MockCrtc(MockGpu *gpu, const std::shared_ptr< MockPlane > &legacyPlane, int pipeIndex, int gamma_size=255)
Definition mock_drm.cpp:217
MockEncoder(MockGpu *gpu, uint32_t possible_crtcs)
Definition mock_drm.cpp:253
MockGpu * gpu
Definition mock_drm.h:133
MockFb(MockGpu *gpu, uint32_t width, uint32_t height)
Definition mock_drm.cpp:262
QMap< uint32_t, uint64_t > deviceCaps
Definition mock_drm.h:165
QList< std::shared_ptr< MockCrtc > > crtcs
Definition mock_drm.h:176
QList< MockFb * > fbs
Definition mock_drm.h:182
std::vector< std::unique_ptr< MockPropertyBlob > > propertyBlobs
Definition mock_drm.h:183
QList< std::shared_ptr< MockEncoder > > encoders
Definition mock_drm.h:173
QList< std::shared_ptr< MockPlane > > planes
Definition mock_drm.h:179
MockCrtc * findCrtc(uint32_t id) const
Definition mock_drm.cpp:67
MockPlane * findPlane(uint32_t id) const
Definition mock_drm.cpp:73
void flipPage(uint32_t crtcId)
Definition mock_drm.cpp:79
MockGpu(int fd, const QString &devNode, int numCrtcs, int gammaSize=255)
Definition mock_drm.cpp:31
QList< std::shared_ptr< MockConnector > > connectors
Definition mock_drm.h:170
MockConnector * findConnector(uint32_t id) const
Definition mock_drm.cpp:61
QList< MockObject * > objects
Definition mock_drm.h:168
MockPropertyBlob * getBlob(uint32_t id) const
Definition mock_drm.cpp:53
int fd
Definition mock_drm.h:161
uint64_t getProp(const QString &propName) const
Definition mock_drm.cpp:105
QList< MockProperty > props
Definition mock_drm.h:63
uint32_t getPropId(const QString &propName) const
Definition mock_drm.cpp:126
uint32_t id
Definition mock_drm.h:62
virtual ~MockObject()
Definition mock_drm.cpp:100
MockObject(MockGpu *gpu)
Definition mock_drm.cpp:93
void setProp(const QString &propName, uint64_t value)
Definition mock_drm.cpp:115
MockGpu * gpu
Definition mock_drm.h:64
MockPlane(MockGpu *gpu, PlaneType type, int crtcIndex)
Definition mock_drm.cpp:232
PlaneType type
Definition mock_drm.h:123
MockPropertyBlob(MockGpu *gpu, const void *data, size_t size)
Definition mock_drm.cpp:149
QString name
Definition mock_drm.h:36
MockObject * obj
Definition mock_drm.h:33
MockProperty(MockObject *obj, QString name, uint64_t initialValue, uint32_t flags, QList< QByteArray > enums={})
Definition mock_drm.cpp:138
int drmModeAtomicAddProperty(drmModeAtomicReqPtr req, uint32_t object_id, uint32_t property_id, uint64_t value)
Definition mock_drm.cpp:930
int drmModeCreateLease(int fd, const uint32_t *objects, int num_objects, int flags, uint32_t *lessee_id)
int drmModeRmFB(int fd, uint32_t bufferId)
Definition mock_drm.cpp:448
void drmModeFreeProperty(drmModePropertyPtr ptr)
Definition mock_drm.cpp:771
int drmModeConnectorSetProperty(int fd, uint32_t connector_id, uint32_t property_id, uint64_t value)
Definition mock_drm.cpp:826
drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd, uint32_t blob_id)
Definition mock_drm.cpp:789
drmModePlaneResPtr drmModeGetPlaneResources(int fd)
Definition mock_drm.cpp:689
void drmModeFreeObjectProperties(drmModeObjectPropertiesPtr ptr)
Definition mock_drm.cpp:881
void drmModeFreePlane(drmModePlanePtr ptr)
int drmHandleEvent(int fd, drmEventContextPtr evctx)
Definition mock_drm.cpp:327
int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth, uint8_t bpp, uint32_t pitch, uint32_t bo_handle, uint32_t *buf_id)
Definition mock_drm.cpp:412
void drmModeFreeEncoder(drmModeEncoderPtr ptr)
#define addProp(name, value, flags)
Definition mock_drm.cpp:165
drmModeResPtr drmModeGetResources(int fd)
Definition mock_drm.cpp:370
int drmModeObjectSetProperty(int fd, uint32_t object_id, uint32_t object_type, uint32_t property_id, uint64_t value)
Definition mock_drm.cpp:893
int drmGetCap(int fd, uint64_t capability, uint64_t *value)
Definition mock_drm.cpp:316
int drmModeAddFB2(int fd, uint32_t width, uint32_t height, uint32_t pixel_format, const uint32_t bo_handles[4], const uint32_t pitches[4], const uint32_t offsets[4], uint32_t *buf_id, uint32_t flags)
Definition mock_drm.cpp:422
int drmModeCreatePropertyBlob(int fd, const void *data, size_t size, uint32_t *id)
drmModeObjectPropertiesPtr drmModeObjectGetProperties(int fd, uint32_t object_id, uint32_t object_type)
Definition mock_drm.cpp:844
drmModeConnectorPtr drmModeGetConnectorCurrent(int fd, uint32_t connector_id)
Definition mock_drm.cpp:662
void drmModeFreeCrtc(drmModeCrtcPtr ptr)
int drmModeRevokeLease(int fd, uint32_t lessee_id)
void drmModeFreeConnector(drmModeConnectorPtr ptr)
drmModeObjectListPtr drmModeGetLease(int fd)
drmModeLesseeListPtr drmModeListLessees(int fd)
int drmModeCrtcSetGamma(int fd, uint32_t crtc_id, uint32_t size, uint16_t *red, uint16_t *green, uint16_t *blue)
Definition mock_drm.cpp:667
void drmModeAtomicFree(drmModeAtomicReqPtr req)
Definition mock_drm.cpp:924
int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y)
Definition mock_drm.cpp:580
drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connectorId)
Definition mock_drm.cpp:622
drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id)
Definition mock_drm.cpp:592
int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, uint32_t x, uint32_t y, uint32_t *connectors, int count, drmModeModeInfoPtr mode)
Definition mock_drm.cpp:509
drmModeAtomicReqPtr drmModeAtomicAlloc(void)
Definition mock_drm.cpp:917
drmVersionPtr drmGetVersion(int fd)
Definition mock_drm.cpp:287
int drmSetClientCap(int fd, uint64_t capability, uint64_t value)
Definition mock_drm.cpp:303
drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId)
Definition mock_drm.cpp:486
int drmIoctl(int fd, unsigned long request, void *arg)
Definition mock_drm.cpp:333
int drmModeDestroyPropertyBlob(int fd, uint32_t id)
int drmModeSetCursor2(int fd, uint32_t crtcId, uint32_t bo_handle, uint32_t width, uint32_t height, int32_t hot_x, int32_t hot_y)
Definition mock_drm.cpp:574
void drmModeFreePlaneResources(drmModePlaneResPtr ptr)
void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr)
Definition mock_drm.cpp:812
drmModePlanePtr drmModeGetPlane(int fd, uint32_t plane_id)
Definition mock_drm.cpp:702
void drmModeFreeResources(drmModeResPtr ptr)
int drmModeSetCursor(int fd, uint32_t crtcId, uint32_t bo_handle, uint32_t width, uint32_t height)
Definition mock_drm.cpp:562
drmModePropertyPtr drmModeGetProperty(int fd, uint32_t propertyId)
Definition mock_drm.cpp:730
#define GPU(fd, error)
Definition mock_drm.cpp:278
int drmModePageFlip(int fd, uint32_t crtc_id, uint32_t fb_id, uint32_t flags, void *user_data)
Definition mock_drm.cpp:672
int drmModeAtomicCommit(int fd, drmModeAtomicReqPtr req, uint32_t flags, void *user_data)
Definition mock_drm.cpp:959
int drmModeAddFB2WithModifiers(int fd, uint32_t width, uint32_t height, uint32_t pixel_format, const uint32_t bo_handles[4], const uint32_t pitches[4], const uint32_t offsets[4], const uint64_t modifier[4], uint32_t *buf_id, uint32_t flags)
Definition mock_drm.cpp:433
void drmFreeVersion(drmVersionPtr ptr)
Definition mock_drm.cpp:296
#define MOCKDRM_DEVICE_CAP_ATOMIC
Definition mock_drm.h:147
PlaneType
Definition mock_drm.h:108
uint32_t prop
Definition mock_drm.h:138
uint64_t value
Definition mock_drm.h:139
uint32_t obj
Definition mock_drm.h:137