diff --git a/autotests/drm/mock_drm.cpp b/autotests/drm/mock_drm.cpp index ebb7c688bd..44745f9ca9 100644 --- a/autotests/drm/mock_drm.cpp +++ b/autotests/drm/mock_drm.cpp @@ -330,15 +330,35 @@ int drmHandleEvent(int fd, drmEventContextPtr evctx) int drmIoctl(int fd, unsigned long request, void *arg) { - GPU(fd, -EINVAL); if (request == DRM_IOCTL_PRIME_FD_TO_HANDLE) { + GPU(fd, -EINVAL); auto args = static_cast(arg); args->handle = 42; // just pass a dummy value so the request doesn't fail return 0; } else if (request == DRM_IOCTL_PRIME_HANDLE_TO_FD) { return -(errno = ENOTSUP); } else if (request == DRM_IOCTL_GEM_CLOSE) { + GPU(fd, -EINVAL); return 0; + } else if (request == DRM_IOCTL_MODE_ATOMIC) { + const auto args = static_cast(arg); + auto req = drmModeAtomicAlloc(); + const uint32_t *const objects = reinterpret_cast(args->objs_ptr); + const uint32_t *const propsCounts = reinterpret_cast(args->count_props_ptr); + const uint32_t *const props = reinterpret_cast(args->props_ptr); + const uint64_t *const values = reinterpret_cast(args->prop_values_ptr); + uint32_t propIndex = 0; + for (uint32_t objIndex = 0; objIndex < args->count_objs; objIndex++) { + const uint32_t objectId = objects[objIndex]; + const uint32_t count = propsCounts[objIndex]; + for (uint32_t i = 0; i < count; i++) { + drmModeAtomicAddProperty(req, objectId, props[propIndex + i], values[propIndex + i]); + } + propIndex += count; + } + int ret = drmModeAtomicCommit(fd, req, args->flags, reinterpret_cast(args->user_data)); + drmModeAtomicFree(req); + return ret; } return -(errno = ENOTSUP); } diff --git a/src/backends/drm/drm_commit.cpp b/src/backends/drm/drm_commit.cpp index 1cce0190fb..a7372b1aa6 100644 --- a/src/backends/drm/drm_commit.cpp +++ b/src/backends/drm/drm_commit.cpp @@ -39,13 +39,12 @@ DrmGpu *DrmCommit::gpu() const DrmAtomicCommit::DrmAtomicCommit(const QVector &pipelines) : DrmCommit(pipelines.front()->gpu()) , m_pipelines(pipelines) - , m_req(drmModeAtomicAlloc()) { } void DrmAtomicCommit::addProperty(const DrmProperty &prop, uint64_t value) { - drmModeAtomicAddProperty(m_req.get(), prop.drmObject()->id(), prop.propId(), value); + m_properties[prop.drmObject()->id()][prop.propId()] = value; } void DrmAtomicCommit::addBlob(const DrmProperty &prop, const std::shared_ptr &blob) @@ -68,27 +67,57 @@ void DrmAtomicCommit::setVrr(DrmCrtc *crtc, bool vrr) bool DrmAtomicCommit::test() { - return drmModeAtomicCommit(gpu()->fd(), m_req.get(), DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_NONBLOCK, this) == 0; + return doCommit(DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_NONBLOCK); } bool DrmAtomicCommit::testAllowModeset() { - return drmModeAtomicCommit(gpu()->fd(), m_req.get(), DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET, this) == 0; + return doCommit(DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET); } bool DrmAtomicCommit::commit() { - return drmModeAtomicCommit(gpu()->fd(), m_req.get(), DRM_MODE_ATOMIC_NONBLOCK | DRM_MODE_PAGE_FLIP_EVENT, this) == 0; + return doCommit(DRM_MODE_ATOMIC_NONBLOCK | DRM_MODE_PAGE_FLIP_EVENT); } bool DrmAtomicCommit::commitModeset() { - return drmModeAtomicCommit(gpu()->fd(), m_req.get(), DRM_MODE_ATOMIC_ALLOW_MODESET, this) == 0; + return doCommit(DRM_MODE_ATOMIC_ALLOW_MODESET); } -drmModeAtomicReq *DrmAtomicCommit::req() const +bool DrmAtomicCommit::doCommit(uint32_t flags) { - return m_req.get(); + std::vector objects; + std::vector propertyCounts; + std::vector propertyIds; + std::vector values; + objects.reserve(m_properties.size()); + propertyCounts.reserve(m_properties.size()); + uint64_t totalPropertiesCount = 0; + for (const auto &[object, properties] : m_properties) { + objects.push_back(object); + propertyCounts.push_back(properties.size()); + totalPropertiesCount += properties.size(); + } + propertyIds.reserve(totalPropertiesCount); + values.reserve(totalPropertiesCount); + for (const auto &[object, properties] : m_properties) { + for (const auto &[property, value] : properties) { + propertyIds.push_back(property); + values.push_back(value); + } + } + drm_mode_atomic commitData{ + .flags = flags, + .count_objs = uint32_t(objects.size()), + .objs_ptr = reinterpret_cast(objects.data()), + .count_props_ptr = reinterpret_cast(propertyCounts.data()), + .props_ptr = reinterpret_cast(propertyIds.data()), + .prop_values_ptr = reinterpret_cast(values.data()), + .reserved = 0, + .user_data = reinterpret_cast(this), + }; + return drmIoctl(m_gpu->fd(), DRM_IOCTL_MODE_ATOMIC, &commitData) == 0; } void DrmAtomicCommit::pageFlipped(std::chrono::nanoseconds timestamp) const diff --git a/src/backends/drm/drm_commit.h b/src/backends/drm/drm_commit.h index 1106bed386..22445e23f8 100644 --- a/src/backends/drm/drm_commit.h +++ b/src/backends/drm/drm_commit.h @@ -67,17 +67,17 @@ public: void pageFlipped(std::chrono::nanoseconds timestamp) const override; - drmModeAtomicReq *req() const; - bool areBuffersReadable() const; bool isVrr() const; private: + bool doCommit(uint32_t flags); + const QVector m_pipelines; - DrmUniquePtr m_req; QHash> m_blobs; std::unordered_map> m_buffers; bool m_vrr = false; + std::unordered_map> m_properties; }; class DrmLegacyCommit : public DrmCommit