KWin
Loading...
Searching...
No Matches
drm_commit.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: 2023 Xaver Hugl <xaver.hugl@gmail.com>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9#include "drm_commit.h"
10#include "drm_blob.h"
11#include "drm_buffer.h"
12#include "drm_connector.h"
13#include "drm_crtc.h"
14#include "drm_gpu.h"
15#include "drm_object.h"
16#include "drm_property.h"
17
18#include <QApplication>
19#include <QThread>
20
21namespace KWin
22{
23
25 : m_gpu(gpu)
26{
27}
28
30{
31 Q_ASSERT(QThread::currentThread() == QApplication::instance()->thread());
32}
33
35{
36 return m_gpu;
37}
38
39DrmAtomicCommit::DrmAtomicCommit(const QList<DrmPipeline *> &pipelines)
40 : DrmCommit(pipelines.front()->gpu())
41 , m_pipelines(pipelines)
42{
43}
44
45void DrmAtomicCommit::addProperty(const DrmProperty &prop, uint64_t value)
46{
47 m_properties[prop.drmObject()->id()][prop.propId()] = value;
48}
49
50void DrmAtomicCommit::addBlob(const DrmProperty &prop, const std::shared_ptr<DrmBlob> &blob)
51{
52 addProperty(prop, blob ? blob->blobId() : 0);
53 m_blobs[&prop] = blob;
54}
55
56void DrmAtomicCommit::addBuffer(DrmPlane *plane, const std::shared_ptr<DrmFramebuffer> &buffer)
57{
58 addProperty(plane->fbId, buffer ? buffer->framebufferId() : 0);
59 m_buffers[plane] = buffer;
60 // atomic commits with IN_FENCE_FD fail with NVidia
61 if (plane->inFenceFd.isValid() && !plane->gpu()->isNVidia()) {
62 addProperty(plane->inFenceFd, buffer ? buffer->syncFd().get() : -1);
63 }
64 m_planes.emplace(plane);
65}
66
67void DrmAtomicCommit::setVrr(DrmCrtc *crtc, bool vrr)
68{
69 addProperty(crtc->vrrEnabled, vrr ? 1 : 0);
70 m_vrr = vrr;
71}
72
74{
75 m_mode = mode;
76}
77
79{
80 return doCommit(DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_NONBLOCK);
81}
82
84{
85 return doCommit(DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET);
86}
87
89{
90 return doCommit(DRM_MODE_ATOMIC_NONBLOCK | DRM_MODE_PAGE_FLIP_EVENT);
91}
92
94{
95 m_modeset = true;
96 return doCommit(DRM_MODE_ATOMIC_ALLOW_MODESET);
97}
98
99bool DrmAtomicCommit::doCommit(uint32_t flags)
100{
101 std::vector<uint32_t> objects;
102 std::vector<uint32_t> propertyCounts;
103 std::vector<uint32_t> propertyIds;
104 std::vector<uint64_t> values;
105 objects.reserve(m_properties.size());
106 propertyCounts.reserve(m_properties.size());
107 uint64_t totalPropertiesCount = 0;
108 for (const auto &[object, properties] : m_properties) {
109 objects.push_back(object);
110 propertyCounts.push_back(properties.size());
111 totalPropertiesCount += properties.size();
112 }
113 propertyIds.reserve(totalPropertiesCount);
114 values.reserve(totalPropertiesCount);
115 for (const auto &[object, properties] : m_properties) {
116 for (const auto &[property, value] : properties) {
117 propertyIds.push_back(property);
118 values.push_back(value);
119 }
120 }
121 drm_mode_atomic commitData{
122 .flags = flags,
123 .count_objs = uint32_t(objects.size()),
124 .objs_ptr = reinterpret_cast<uint64_t>(objects.data()),
125 .count_props_ptr = reinterpret_cast<uint64_t>(propertyCounts.data()),
126 .props_ptr = reinterpret_cast<uint64_t>(propertyIds.data()),
127 .prop_values_ptr = reinterpret_cast<uint64_t>(values.data()),
128 .reserved = 0,
129 .user_data = reinterpret_cast<uint64_t>(this),
130 };
131 return drmIoctl(m_gpu->fd(), DRM_IOCTL_MODE_ATOMIC, &commitData) == 0;
132}
133
134void DrmAtomicCommit::pageFlipped(std::chrono::nanoseconds timestamp) const
135{
136 Q_ASSERT(QThread::currentThread() == QApplication::instance()->thread());
137 for (const auto &[plane, buffer] : m_buffers) {
138 plane->setCurrentBuffer(buffer);
139 }
141 if (m_modeset) {
143 } else if (m_cursorOnly) {
145 }
146 for (const auto pipeline : std::as_const(m_pipelines)) {
147 pipeline->pageFlipped(timestamp, type, m_mode);
148 }
149}
150
152{
153 return std::all_of(m_buffers.begin(), m_buffers.end(), [](const auto &pair) {
154 const auto &[plane, buffer] = pair;
155 return !buffer || buffer->isReadable();
156 });
157}
158
159void DrmAtomicCommit::setDeadline(std::chrono::steady_clock::time_point deadline)
160{
161 for (const auto &[plane, buffer] : m_buffers) {
162 if (buffer) {
163 buffer->setDeadline(deadline);
164 }
165 }
166}
167
168std::optional<bool> DrmAtomicCommit::isVrr() const
169{
170 return m_vrr;
171}
172
173const std::unordered_set<DrmPlane *> &DrmAtomicCommit::modifiedPlanes() const
174{
175 return m_planes;
176}
177
179{
180 for (const auto &[obj, properties] : onTop->m_properties) {
181 auto &ownProperties = m_properties[obj];
182 for (const auto &[prop, value] : properties) {
183 ownProperties[prop] = value;
184 }
185 }
186 for (const auto &[plane, buffer] : onTop->m_buffers) {
187 m_buffers[plane] = buffer;
188 m_planes.emplace(plane);
189 }
190 for (const auto &[prop, blob] : onTop->m_blobs) {
191 m_blobs[prop] = blob;
192 }
193 if (onTop->m_vrr) {
194 m_vrr = onTop->m_vrr;
195 }
196 m_cursorOnly &= onTop->isCursorOnly();
197}
198
200{
201 m_cursorOnly = cursor;
202}
203
205{
206 return m_cursorOnly;
207}
208
209DrmLegacyCommit::DrmLegacyCommit(DrmPipeline *pipeline, const std::shared_ptr<DrmFramebuffer> &buffer)
210 : DrmCommit(pipeline->gpu())
211 , m_pipeline(pipeline)
212 , m_buffer(buffer)
213{
214}
215
217{
218 m_modeset = true;
219 uint32_t connectorId = connector->id();
220 if (drmModeSetCrtc(gpu()->fd(), m_pipeline->crtc()->id(), m_buffer->framebufferId(), 0, 0, &connectorId, 1, mode->nativeMode()) == 0) {
221 m_pipeline->crtc()->setCurrent(m_buffer);
222 return true;
223 } else {
224 return false;
225 }
226}
227
229{
230 m_mode = mode;
231 uint32_t flags = DRM_MODE_PAGE_FLIP_EVENT;
233 flags |= DRM_MODE_PAGE_FLIP_ASYNC;
234 }
235 return drmModePageFlip(gpu()->fd(), m_pipeline->crtc()->id(), m_buffer->framebufferId(), flags, this) == 0;
236}
237
238void DrmLegacyCommit::pageFlipped(std::chrono::nanoseconds timestamp) const
239{
240 Q_ASSERT(QThread::currentThread() == QApplication::instance()->thread());
241 m_pipeline->crtc()->setCurrent(m_buffer);
242 m_pipeline->pageFlipped(timestamp, m_modeset ? DrmPipeline::PageflipType::Modeset : DrmPipeline::PageflipType::Normal, m_mode);
243}
244}
void setPresentationMode(PresentationMode mode)
const std::unordered_set< DrmPlane * > & modifiedPlanes() const
void addProperty(const DrmProperty &prop, uint64_t value)
void merge(DrmAtomicCommit *onTop)
void setVrr(DrmCrtc *crtc, bool vrr)
DrmAtomicCommit(const QList< DrmPipeline * > &pipelines)
bool areBuffersReadable() const
void addBuffer(DrmPlane *plane, const std::shared_ptr< DrmFramebuffer > &buffer)
void addBlob(const DrmProperty &prop, const std::shared_ptr< DrmBlob > &blob)
void setDeadline(std::chrono::steady_clock::time_point deadline)
bool isCursorOnly() const
void setCursorOnly(bool cursor)
std::optional< bool > isVrr() const
void pageFlipped(std::chrono::nanoseconds timestamp) const override
virtual ~DrmCommit()
DrmGpu *const m_gpu
Definition drm_commit.h:47
DrmGpu * gpu() const
DrmCommit(DrmGpu *gpu)
drmModeModeInfo * nativeMode()
DrmProperty vrrEnabled
Definition drm_crtc.h:45
void setCurrent(const std::shared_ptr< DrmFramebuffer > &buffer)
Definition drm_crtc.cpp:71
bool isNVidia() const
Definition drm_gpu.cpp:698
int fd() const
Definition drm_gpu.cpp:648
DrmLegacyCommit(DrmPipeline *pipeline, const std::shared_ptr< DrmFramebuffer > &buffer)
void pageFlipped(std::chrono::nanoseconds timestamp) const override
bool doPageflip(PresentationMode mode)
bool doModeset(DrmConnector *connector, DrmConnectorMode *mode)
uint32_t id() const
DrmGpu * gpu() const
void pageFlipped(std::chrono::nanoseconds timestamp, PageflipType type, PresentationMode mode)
DrmCrtc * crtc() const
DrmProperty inFenceFd
Definition drm_plane.h:93
DrmProperty fbId
Definition drm_plane.h:83
DrmObject * drmObject() const
uint32_t propId() const
bool isValid() const
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
int drmIoctl(int fd, unsigned long request, void *arg)
Definition mock_drm.cpp:333
int drmModePageFlip(int fd, uint32_t crtc_id, uint32_t fb_id, uint32_t flags, void *user_data)
Definition mock_drm.cpp:672
Session::Type type
Definition session.cpp:17
PresentationMode
Definition globals.h:276