13#include <libxcvt/libxcvt.h>
24static QMap<int, MockGpu*> s_gpus;
35 s_gpus.insert(
fd,
this);
36 for (
int i = 0; i < numCrtcs; i++) {
56 return propBlob->id == id;
63 auto it = std::find_if(
connectors.constBegin(),
connectors.constEnd(), [
id](
const auto &
c){return c->id == id;});
69 auto it = std::find_if(
crtcs.constBegin(),
crtcs.constEnd(), [
id](
const auto &
c){return c->id == id;});
75 auto it = std::find_if(
planes.constBegin(),
planes.constEnd(), [
id](
const auto &
p){return p->id == id;});
83 for (
const auto &plane : std::as_const(
planes)) {
85 plane->currentFb = plane->nextFb;
94 : id(gpu->idCounter++)
107 for (
const auto &prop : std::as_const(
props)) {
108 if (prop.name == propName) {
117 for (
auto &prop :
props) {
118 if (prop.name == propName) {
128 for (
const auto &prop : std::as_const(
props)) {
129 if (prop.name == propName) {
140 , id(obj->gpu->idCounter++)
143 , value(initialValue)
146 qDebug(
"Added property %s with id %u to object %u", qPrintable(
name),
id,
obj->
id);
151 , id(gpu->idCounter++)
165#define addProp(name, value, flags) props << MockProperty(this, QStringLiteral(name), value, flags)
169 , connection(DRM_MODE_CONNECTED)
170 , type(DRM_MODE_CONNECTOR_DisplayPort)
171 , encoder(std::make_shared<
MockEncoder>(gpu, 0xFF))
174 addProp(
"CRTC_ID", 0, DRM_MODE_PROP_ATOMIC);
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);
180 addProp(
"DPMS", DRM_MODE_DPMS_OFF, 0);
181 addProp(
"EDID", 0, DRM_MODE_PROP_BLOB | DRM_MODE_PROP_IMMUTABLE);
188 auto modeInfo = libxcvt_gen_mode_info(width, height, refreshRate,
false,
false);
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,
197 .vdisplay = uint16_t(modeInfo->vdisplay),
198 .vsync_start = modeInfo->vsync_start,
199 .vsync_end = modeInfo->vsync_end,
200 .vtotal = modeInfo->vtotal,
202 .vrefresh = uint32_t(modeInfo->vrefresh),
203 .flags = modeInfo->mode_flags,
204 .type = DRM_MODE_TYPE_DRIVER,
207 mode.type |= DRM_MODE_TYPE_PREFERRED;
209 sprintf(mode.name,
"%dx%d@%d", width, height, mode.vrefresh);
211 modes.push_back(mode);
219 , pipeIndex(pipeIndex)
220 , gamma_size(gamma_size)
221 , legacyPlane(legacyPlane)
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);
234 , possibleCrtcs(1 << crtcIndex)
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);
255 , possible_crtcs(possible_crtcs)
263 : id(gpu->idCounter++)
278#define GPU(fd, error) \
279 auto gpu = getGpu(fd); \
281 qWarning("invalid fd %d", fd); \
285 std::scoped_lock lock(gpu->m_mutex);
290 drmVersionPtr ptr =
new drmVersion;
291 ptr->name =
new char[gpu->name.size() + 1];
292 strcpy(ptr->name, gpu->name.data());
306 if (capability == DRM_CLIENT_CAP_ATOMIC) {
308 return -(errno = ENOTSUP);
310 qDebug(
"Setting DRM_CLIENT_CAP_ATOMIC to %lu", value);
312 gpu->clientCaps.insert(capability, value);
316int drmGetCap(
int fd, uint64_t capability, uint64_t *value)
319 if (gpu->deviceCaps.contains(capability)) {
320 *value = gpu->deviceCaps[capability];
323 qDebug(
"Could not find capability %lu", capability);
324 return -(errno = EINVAL);
330 return -(errno = ENOTSUP);
333int drmIoctl(
int fd,
unsigned long request,
void *arg)
335 if (request == DRM_IOCTL_PRIME_FD_TO_HANDLE) {
337 auto args =
static_cast<drm_prime_handle *
>(arg);
340 }
else if (request == DRM_IOCTL_PRIME_HANDLE_TO_FD) {
341 return -(errno = ENOTSUP);
342 }
else if (request == DRM_IOCTL_GEM_CLOSE) {
345 }
else if (request == DRM_IOCTL_MODE_ATOMIC) {
346 const auto args =
static_cast<drm_mode_atomic *
>(arg);
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++) {
361 int ret =
drmModeAtomicCommit(fd, req, args->flags,
reinterpret_cast<void *
>(args->user_data));
364 }
else if (request == DRM_IOCTL_MODE_RMFB) {
365 drmModeRmFB(fd, *
static_cast<const uint32_t *
>(arg));
367 return -(errno = ENOTSUP);
373 drmModeResPtr res =
new drmModeRes;
375 res->count_connectors = gpu->connectors.count();
376 res->connectors = res->count_connectors ?
new uint32_t[res->count_connectors] :
nullptr;
378 for (
const auto &conn : std::as_const(gpu->connectors)) {
379 res->connectors[i++] = conn->id;
382 res->count_encoders = gpu->encoders.count();
383 res->encoders = res->count_encoders ?
new uint32_t[res->count_encoders] :
nullptr;
385 for (
const auto &enc : std::as_const(gpu->encoders)) {
386 res->encoders[i++] = enc->id;
389 res->count_crtcs = gpu->crtcs.count();
390 res->crtcs = res->count_crtcs ?
new uint32_t[res->count_crtcs] :
nullptr;
392 for (
const auto &crtc : std::as_const(gpu->crtcs)) {
393 res->crtcs[i++] = crtc->id;
396 res->count_fbs = gpu->fbs.count();
397 res->fbs = res->count_fbs ?
new uint32_t[res->count_fbs] :
nullptr;
399 for (
const auto &fb : std::as_const(gpu->fbs)) {
400 res->fbs[i++] = fb->id;
405 res->max_width = 2 << 14;
406 res->max_height = 2 << 14;
412int drmModeAddFB(
int fd, uint32_t width, uint32_t height, uint8_t depth,
413 uint8_t bpp, uint32_t pitch, uint32_t bo_handle,
417 auto fb =
new MockFb(gpu, width, 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)
428 auto fb =
new MockFb(gpu, width, 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,
440 if (!gpu->deviceCaps.contains(DRM_CAP_ADDFB2_MODIFIERS)) {
441 return -(errno = ENOTSUP);
443 auto fb =
new MockFb(gpu, width, height);
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);
458 for (
const auto &plane : std::as_const(gpu->planes)) {
459 if (plane->nextFb == fb) {
460 plane->nextFb =
nullptr;
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;
468 auto crtc = gpu->findCrtc(plane->getProp(QStringLiteral(
"CRTC_ID")));
470 crtc->setProp(QStringLiteral(
"ACTIVE"), 0);
471 qWarning(
"deactvating crtc %u", crtc->id);
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);
489 if (
auto crtc = gpu->findCrtc(crtcId)) {
490 drmModeCrtcPtr c =
new drmModeCrtc;
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;
498 c->width = crtc->mode.hdisplay;
499 c->height = crtc->mode.vdisplay;
503 qWarning(
"invalid crtcId %u passed to drmModeGetCrtc", crtcId);
510 uint32_t x, uint32_t y, uint32_t *connectors,
int count,
511 drmModeModeInfoPtr mode)
514 auto crtc = gpu->findCrtc(crtcId);
516 qWarning(
"invalid crtcId %u passed to drmModeSetCrtc", crtcId);
517 return -(errno = EINVAL);
519 auto oldModeBlob = crtc->getProp(QStringLiteral(
"MODE_ID"));
520 uint32_t modeBlob = 0;
526 req->legacyEmulation =
true;
529 QList<uint32_t> conns;
530 for (
int i = 0; i < count; i++) {
531 conns << connectors[i];
533 for (
const auto &conn : std::as_const(gpu->connectors)) {
534 if (conns.contains(conn->id)) {
536 conns.removeOne(conn->id);
537 }
else if (conn->getProp(QStringLiteral(
"CRTC_ID")) == crtc->id) {
541 if (!conns.isEmpty()) {
542 for (
const auto &c : std::as_const(conns)) {
543 qWarning(
"invalid connector %u passed to drmModeSetCrtc", c);
546 return -(errno = EINVAL);
548 drmModeAtomicAddProperty(req, crtc->legacyPlane->id, crtc->legacyPlane->getPropId(QStringLiteral(
"CRTC_ID")), modeBlob && count ? crtc->id : 0);
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);
562int drmModeSetCursor(
int fd, uint32_t crtcId, uint32_t bo_handle, uint32_t width, uint32_t height)
565 if (
auto crtc = gpu->findCrtc(crtcId)) {
566 crtc->cursorRect.setSize(QSize(width, height));
569 qWarning(
"invalid crtcId %u passed to drmModeSetCursor", crtcId);
570 return -(errno = EINVAL);
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)
577 return -(errno = ENOTSUP);
583 if (
auto crtc = gpu->findCrtc(crtcId)) {
584 crtc->cursorRect.moveTo(x, y);
587 qWarning(
"invalid crtcId %u passed to drmModeMoveCursor", crtcId);
588 return -(errno = EINVAL);
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);
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;
609 gpu->drmEncoders << enc;
620static std::atomic<int> autoIncrementedConnectorId{};
625 if (
auto conn = gpu->findConnector(connectorId)) {
626 drmModeConnectorPtr c =
new drmModeConnector{};
627 c->connector_id = conn->id;
628 c->connection = conn->connection;
630 c->connector_type = conn->type;
631 c->connector_type_id = autoIncrementedConnectorId++;
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;
637 c->encoders[0] = conn->encoder->id;
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];
646 c->subpixel = DRM_MODE_SUBPIXEL_HORIZONTAL_RGB;
651 c->prop_values =
nullptr;
653 gpu->drmConnectors << c;
656 qWarning(
"invalid connectorId %u passed to drmModeGetConnector", connectorId);
667int drmModeCrtcSetGamma(
int fd, uint32_t crtc_id, uint32_t size, uint16_t *red, uint16_t *green, uint16_t *blue)
669 return -(errno = ENOTSUP);
672int drmModePageFlip(
int fd, uint32_t crtc_id, uint32_t fb_id, uint32_t flags,
void *user_data)
675 auto crtc = gpu->findCrtc(crtc_id);
677 qWarning(
"invalid crtc_id %u passed to drmModePageFlip", crtc_id);
678 return -(errno = EINVAL);
681 req->legacyEmulation =
true;
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;
698 gpu->drmPlaneRes << res;
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;
717 p->count_formats = 0;
718 p->formats =
nullptr;
724 qWarning(
"invalid plane_id %u passed to drmModeGetPlane", plane_id);
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());
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;
747 p->blob_ids =
nullptr;
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;
758 p->values =
new uint64_t[1];
759 p->values[0] = prop.value;
766 qWarning(
"invalid propertyId %u passed to drmModeGetProperty", propertyId);
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;
795 auto it = std::find_if(gpu->propertyBlobs.begin(), gpu->propertyBlobs.end(), [blob_id](
const auto &blob) {
796 return blob->id == blob_id;
798 if (it == gpu->propertyBlobs.end()) {
799 qWarning(
"invalid blob_id %u passed to drmModeGetPropertyBlob", blob_id);
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);
817 for (
const auto &gpu : std::as_const(s_gpus)) {
818 if (gpu->drmPropertyBlobs.removeOne(ptr)) {
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;
840 return DRM_MODE_OBJECT_ANY;
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);
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);
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)) {
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];
871 for (
const auto &prop : std::as_const(props)) {
872 p->props[i] = prop.id;
873 p->prop_values[i] = prop.value;
876 gpu->drmObjectProperties << p;
883 for (
const auto &gpu : std::as_const(s_gpus)) {
884 if (gpu->drmObjectProperties.removeOne(ptr)) {
886 delete[] ptr->prop_values;
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);
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);
907 req->legacyEmulation =
true;
915static QList<drmModeAtomicReqPtr> s_atomicReqs;
919 auto req =
new drmModeAtomicReq;
926 s_atomicReqs.removeOne(req);
933 return -(errno = EINVAL);
937 p.
prop = property_id;
940 return req->props.count();
943static bool checkIfEqual(
const drmModeModeInfo &one,
const drmModeModeInfo &two)
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;
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);
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);
979 QList<MockConnector> connCopies;
980 for (
const auto &conn : std::as_const(gpu->connectors)) {
983 QList<MockCrtc> crtcCopies;
984 for (
const auto &crtc : std::as_const(gpu->crtcs)) {
987 QList<MockPlane> planeCopies;
988 for (
const auto &plane : std::as_const(gpu->planes)) {
989 planeCopies << *plane;
992 QList<MockObject *> objects;
993 for (
int i = 0; i < connCopies.count(); i++) {
994 objects << &connCopies[i];
996 for (
int i = 0; i < crtcCopies.count(); i++) {
997 objects << &crtcCopies[i];
999 for (
int i = 0; i < planeCopies.count(); i++) {
1000 objects << &planeCopies[i];
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);
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);
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);
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);
1030 prop->value = p.value;
1038 QList<MockConnector *> conns;
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")));
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);
1053 pipeline.crtc = &crtcCopies[i];
1054 pipelines << pipeline;
1057 for (
int i = 0; i < connCopies.count(); i++) {
1058 if (
auto crtc = connCopies[i].getProp(QStringLiteral(
"CRTC_ID"))) {
1060 for (
int p = 0; p < pipelines.count(); p++) {
1061 if (pipelines[p].crtc->id == crtc) {
1062 pipelines[p].conns << &connCopies[i];
1068 qWarning(
"CRTC_ID of connector %u points to inactive or wrong crtc", connCopies[i].
id);
1069 return -(errno = EINVAL);
1073 for (
int i = 0; i < planeCopies.count(); i++) {
1074 if (
auto crtc = planeCopies[i].getProp(QStringLiteral(
"CRTC_ID"))) {
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);
1085 pipelines[p].primaryPlane = &planeCopies[i];
1092 qWarning(
"CRTC_ID of plane %u points to inactive or wrong crtc", planeCopies[i].
id);
1093 return -(errno = EINVAL);
1095 auto fbId = planeCopies[i].getProp(QStringLiteral(
"FB_ID"));
1097 qWarning(
"FB_ID of active plane %u is 0", planeCopies[i].
id);
1098 return -(errno = EINVAL);
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);
1105 planeCopies[i].nextFb = *it;
1107 planeCopies[i].nextFb =
nullptr;
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);
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();
1124 qWarning(
"mode on crtc %u is incompatible with connector %u", p.crtc->id, conn->id);
1125 return -(errno = EINVAL);
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);
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);
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);
1159 if (flags & DRM_MODE_PAGE_FLIP_EVENT) {
1171 if (!data || !size || !
id) {
1172 return -(errno = EINVAL);
1174 auto blob = std::make_unique<MockPropertyBlob>(gpu, data, size);
1176 gpu->propertyBlobs.push_back(std::move(blob));
1183 auto it = std::remove_if(gpu->propertyBlobs.begin(), gpu->propertyBlobs.end(), [
id](
const auto &blob) {
1184 return blob->id == id;
1186 if (it == gpu->propertyBlobs.end()) {
1187 return -(errno = EINVAL);
1189 gpu->propertyBlobs.erase(it, gpu->propertyBlobs.end());
1196 return -(errno = ENOTSUP);
1211 return -(errno = ENOTSUP);
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;
1229 for (
const auto &gpu : std::as_const(s_gpus)) {
1230 if (gpu->drmPlaneRes.removeOne(ptr)) {
1231 delete[] ptr->planes;
1239 for (
const auto &gpu : std::as_const(s_gpus)) {
1240 if (gpu->drmCrtcs.removeOne(ptr)) {
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;
1264 for (
const auto &gpu : std::as_const(s_gpus)) {
1265 if (gpu->drmEncoders.removeOne(ptr)) {
1275 for (
const auto &gpu : std::as_const(s_gpus)) {
1276 if (gpu->drmPlanes.removeOne(ptr)) {
std::shared_ptr< MockEncoder > encoder
MockConnector(MockGpu *gpu, bool nonDesktop=false)
QList< drmModeModeInfo > modes
void addMode(uint32_t width, uint32_t height, float refreshRate, bool preferred=false)
MockCrtc(MockGpu *gpu, const std::shared_ptr< MockPlane > &legacyPlane, int pipeIndex, int gamma_size=255)
MockEncoder(MockGpu *gpu, uint32_t possible_crtcs)
MockFb(MockGpu *gpu, uint32_t width, uint32_t height)
QMap< uint32_t, uint64_t > deviceCaps
QList< std::shared_ptr< MockCrtc > > crtcs
std::vector< std::unique_ptr< MockPropertyBlob > > propertyBlobs
QList< std::shared_ptr< MockEncoder > > encoders
QList< std::shared_ptr< MockPlane > > planes
MockCrtc * findCrtc(uint32_t id) const
MockPlane * findPlane(uint32_t id) const
void flipPage(uint32_t crtcId)
MockGpu(int fd, const QString &devNode, int numCrtcs, int gammaSize=255)
QList< std::shared_ptr< MockConnector > > connectors
MockConnector * findConnector(uint32_t id) const
QList< MockObject * > objects
MockPropertyBlob * getBlob(uint32_t id) const
uint64_t getProp(const QString &propName) const
QList< MockProperty > props
uint32_t getPropId(const QString &propName) const
void setProp(const QString &propName, uint64_t value)
MockPlane(MockGpu *gpu, PlaneType type, int crtcIndex)
MockPropertyBlob(MockGpu *gpu, const void *data, size_t size)
MockProperty(MockObject *obj, QString name, uint64_t initialValue, uint32_t flags, QList< QByteArray > enums={})
int drmModeAtomicAddProperty(drmModeAtomicReqPtr req, uint32_t object_id, uint32_t property_id, uint64_t value)
int drmModeCreateLease(int fd, const uint32_t *objects, int num_objects, int flags, uint32_t *lessee_id)
int drmModeRmFB(int fd, uint32_t bufferId)
void drmModeFreeProperty(drmModePropertyPtr ptr)
int drmModeConnectorSetProperty(int fd, uint32_t connector_id, uint32_t property_id, uint64_t value)
drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd, uint32_t blob_id)
drmModePlaneResPtr drmModeGetPlaneResources(int fd)
void drmModeFreeObjectProperties(drmModeObjectPropertiesPtr ptr)
void drmModeFreePlane(drmModePlanePtr ptr)
int drmHandleEvent(int fd, drmEventContextPtr evctx)
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)
void drmModeFreeEncoder(drmModeEncoderPtr ptr)
#define addProp(name, value, flags)
drmModeResPtr drmModeGetResources(int fd)
int drmModeObjectSetProperty(int fd, uint32_t object_id, uint32_t object_type, uint32_t property_id, uint64_t value)
int drmGetCap(int fd, uint64_t capability, uint64_t *value)
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)
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)
drmModeConnectorPtr drmModeGetConnectorCurrent(int fd, uint32_t connector_id)
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)
void drmModeAtomicFree(drmModeAtomicReqPtr req)
int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y)
drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connectorId)
drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id)
int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, uint32_t x, uint32_t y, uint32_t *connectors, int count, drmModeModeInfoPtr mode)
drmModeAtomicReqPtr drmModeAtomicAlloc(void)
drmVersionPtr drmGetVersion(int fd)
int drmSetClientCap(int fd, uint64_t capability, uint64_t value)
drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId)
int drmIoctl(int fd, unsigned long request, void *arg)
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)
void drmModeFreePlaneResources(drmModePlaneResPtr ptr)
void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr)
drmModePlanePtr drmModeGetPlane(int fd, uint32_t plane_id)
void drmModeFreeResources(drmModeResPtr ptr)
int drmModeSetCursor(int fd, uint32_t crtcId, uint32_t bo_handle, uint32_t width, uint32_t height)
drmModePropertyPtr drmModeGetProperty(int fd, uint32_t propertyId)
int drmModePageFlip(int fd, uint32_t crtc_id, uint32_t fb_id, uint32_t flags, void *user_data)
int drmModeAtomicCommit(int fd, drmModeAtomicReqPtr req, uint32_t flags, void *user_data)
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)
void drmFreeVersion(drmVersionPtr ptr)
#define MOCKDRM_DEVICE_CAP_ATOMIC