Changeset View
Standalone View
plugins/platforms/drm/drm_backend.cpp
Show All 13 Lines | |||||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | 15 | GNU General Public License for more details. | ||
16 | 16 | | |||
17 | You should have received a copy of the GNU General Public License | 17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
19 | *********************************************************************/ | 19 | *********************************************************************/ | ||
20 | #include "drm_backend.h" | 20 | #include "drm_backend.h" | ||
21 | #include "drm_output.h" | 21 | #include "drm_output.h" | ||
22 | #include "drm_object_connector.h" | ||||
23 | #include "drm_object_crtc.h" | ||||
24 | #include "drm_object_plane.h" | ||||
22 | #include "composite.h" | 25 | #include "composite.h" | ||
23 | #include "cursor.h" | 26 | #include "cursor.h" | ||
24 | #include "logging.h" | 27 | #include "logging.h" | ||
25 | #include "logind.h" | 28 | #include "logind.h" | ||
26 | #include "main.h" | 29 | #include "main.h" | ||
27 | #include "scene_qpainter_drm_backend.h" | 30 | #include "scene_qpainter_drm_backend.h" | ||
28 | #include "screens_drm.h" | 31 | #include "screens_drm.h" | ||
29 | #include "udev.h" | 32 | #include "udev.h" | ||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Line(s) | 81 | if (m_gbmDevice) { | |||
79 | gbm_device_destroy(m_gbmDevice); | 82 | gbm_device_destroy(m_gbmDevice); | ||
80 | } | 83 | } | ||
81 | #endif | 84 | #endif | ||
82 | if (m_fd >= 0) { | 85 | if (m_fd >= 0) { | ||
83 | // wait for pageflips | 86 | // wait for pageflips | ||
84 | while (m_pageFlipsPending != 0) { | 87 | while (m_pageFlipsPending != 0) { | ||
85 | QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents); | 88 | QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents); | ||
86 | } | 89 | } | ||
90 | qDeleteAll(m_planes); | ||||
87 | qDeleteAll(m_outputs); | 91 | qDeleteAll(m_outputs); | ||
88 | delete m_cursor[0]; | 92 | delete m_cursor[0]; | ||
89 | delete m_cursor[1]; | 93 | delete m_cursor[1]; | ||
90 | close(m_fd); | 94 | close(m_fd); | ||
91 | } | 95 | } | ||
92 | } | 96 | } | ||
93 | 97 | | |||
94 | void DrmBackend::init() | 98 | void DrmBackend::init() | ||
▲ Show 20 Lines • Show All 142 Lines • ▼ Show 20 Line(s) | 237 | [this] { | |||
237 | drmEventContext e; | 241 | drmEventContext e; | ||
238 | memset(&e, 0, sizeof e); | 242 | memset(&e, 0, sizeof e); | ||
239 | e.version = DRM_EVENT_CONTEXT_VERSION; | 243 | e.version = DRM_EVENT_CONTEXT_VERSION; | ||
240 | e.page_flip_handler = pageFlipHandler; | 244 | e.page_flip_handler = pageFlipHandler; | ||
241 | drmHandleEvent(m_fd, &e); | 245 | drmHandleEvent(m_fd, &e); | ||
242 | } | 246 | } | ||
243 | ); | 247 | ); | ||
244 | m_drmId = device->sysNum(); | 248 | m_drmId = device->sysNum(); | ||
249 | | ||||
250 | // trying to activate Atomic Mode Setting (this means also Universal Planes) | ||||
251 | if (qEnvironmentVariableIsSet("KWIN_DRM_AMS")) { | ||||
252 | if (drmSetClientCap(m_fd, DRM_CLIENT_CAP_ATOMIC, 1) == 0) { | ||||
253 | qCDebug(KWIN_DRM) << "Using Atomic Mode Setting."; | ||||
254 | m_atomicModeSetting = true; | ||||
255 | | ||||
256 | ScopedDrmPointer<drmModePlaneRes, &drmModeFreePlaneResources> planeResources(drmModeGetPlaneResources(m_fd)); | ||||
257 | if (!planeResources) { | ||||
258 | qCWarning(KWIN_DRM) << "Failed to get plane resources. Falling back to legacy mode"; | ||||
259 | m_atomicModeSetting = false; | ||||
260 | } | ||||
261 | | ||||
262 | if (m_atomicModeSetting) { | ||||
263 | qCDebug(KWIN_DRM) << "Number of planes:" << planeResources->count_planes; | ||||
264 | | ||||
265 | // create the plane objects | ||||
266 | for (unsigned int i = 0; i < planeResources->count_planes; ++i) { | ||||
267 | drmModePlane *kplane = drmModeGetPlane(m_fd, planeResources->planes[i]); | ||||
268 | DrmPlane *p = new DrmPlane(kplane->plane_id, m_fd); | ||||
269 | | ||||
270 | if (p->init()) { | ||||
271 | p->setPossibleCrtcs(kplane->possible_crtcs); | ||||
272 | p->setFormats(kplane->formats, kplane->count_formats); | ||||
273 | m_planes << p; | ||||
274 | } else { | ||||
275 | delete p; | ||||
276 | } | ||||
277 | } | ||||
278 | | ||||
279 | if (m_planes.isEmpty()) { | ||||
280 | qCWarning(KWIN_DRM) << "Failed to create any plane. Falling back to legacy mode"; | ||||
281 | m_atomicModeSetting = false; | ||||
282 | } | ||||
283 | } | ||||
284 | } else { | ||||
285 | qCWarning(KWIN_DRM) << "drmSetClientCap for Atomic Mode Setting failed. Using legacy mode."; | ||||
286 | } | ||||
287 | } | ||||
288 | | ||||
245 | queryResources(); | 289 | queryResources(); | ||
246 | if (m_outputs.isEmpty()) { | 290 | if (m_outputs.isEmpty()) { | ||
247 | qCWarning(KWIN_DRM) << "No outputs, cannot render, will terminate now"; | 291 | qCWarning(KWIN_DRM) << "No outputs, cannot render, will terminate now"; | ||
248 | emit initFailed(); | 292 | emit initFailed(); | ||
249 | return; | 293 | return; | ||
250 | } | 294 | } | ||
251 | 295 | | |||
252 | // setup udevMonitor | 296 | // setup udevMonitor | ||
Show All 17 Lines | 311 | if (device->hasProperty("HOTPLUG", "1")) { | |||
270 | m_cursorIndex = (m_cursorIndex + 1) % 2; | 314 | m_cursorIndex = (m_cursorIndex + 1) % 2; | ||
271 | updateCursor(); | 315 | updateCursor(); | ||
272 | } | 316 | } | ||
273 | } | 317 | } | ||
274 | ); | 318 | ); | ||
275 | m_udevMonitor->enable(); | 319 | m_udevMonitor->enable(); | ||
276 | } | 320 | } | ||
277 | } | 321 | } | ||
278 | setReady(true); | 322 | setReady(true); | ||
graesslin: nitpick | |||||
279 | 323 | | |||
280 | initCursor(); | 324 | initCursor(); | ||
281 | } | 325 | } | ||
282 | 326 | | |||
283 | void DrmBackend::queryResources() | 327 | void DrmBackend::queryResources() | ||
284 | { | 328 | { | ||
285 | if (m_fd < 0) { | 329 | if (m_fd < 0) { | ||
286 | return; | 330 | return; | ||
Show All 12 Lines | 342 | if (!connector) { | |||
299 | continue; | 343 | continue; | ||
300 | } | 344 | } | ||
301 | if (connector->connection != DRM_MODE_CONNECTED) { | 345 | if (connector->connection != DRM_MODE_CONNECTED) { | ||
302 | continue; | 346 | continue; | ||
303 | } | 347 | } | ||
304 | if (connector->count_modes == 0) { | 348 | if (connector->count_modes == 0) { | ||
305 | continue; | 349 | continue; | ||
306 | } | 350 | } | ||
307 | if (DrmOutput *o = findOutput(connector->connector_id)) { | 351 | if (DrmOutput *o = findOutput(connector->connector_id)) { | ||
graesslin: nitpick | |||||
308 | connectedOutputs << o; | 352 | connectedOutputs << o; | ||
309 | continue; | 353 | continue; | ||
310 | } | 354 | } | ||
311 | bool crtcFound = false; | 355 | bool crtcFound = false; | ||
312 | const quint32 crtcId = findCrtc(resources.data(), connector.data(), &crtcFound); | 356 | const quint32 crtcId = findCrtc(resources.data(), connector.data(), &crtcFound); | ||
313 | if (!crtcFound) { | 357 | if (!crtcFound) { | ||
314 | continue; | 358 | continue; | ||
315 | } | 359 | } | ||
316 | ScopedDrmPointer<_drmModeCrtc, &drmModeFreeCrtc> crtc(drmModeGetCrtc(m_fd, crtcId)); | 360 | ScopedDrmPointer<_drmModeCrtc, &drmModeFreeCrtc> crtc(drmModeGetCrtc(m_fd, crtcId)); | ||
317 | if (!crtc) { | 361 | if (!crtc) { | ||
318 | continue; | 362 | continue; | ||
319 | } | 363 | } | ||
320 | DrmOutput *drmOutput = new DrmOutput(this); | 364 | DrmOutput *drmOutput = new DrmOutput(this); | ||
321 | connect(drmOutput, &DrmOutput::dpmsChanged, this, &DrmBackend::outputDpmsChanged); | 365 | connect(drmOutput, &DrmOutput::dpmsChanged, this, &DrmBackend::outputDpmsChanged); | ||
322 | drmOutput->m_crtcId = crtcId; | 366 | drmOutput->m_crtcId = crtcId; | ||
would it make sense to also create the Crtc and Connector in the non AMS mode? My thinking is to reduce the differences graesslin: would it make sense to also create the Crtc and Connector in the non AMS mode? My thinking is… | |||||
I think we talked about this topic already. The problem is, that DrmCrtc and DrmConnector ask the kernel for properties, which are only available in AMS, specifically DrmConnector asks for the atomic property CRTC_ID, which I know of being atomic. The properties MODE_ID and ACTIVE of DrmCrtc could also be atomically, but I couldn't find any informations in this regard. romangg: I think we talked about this topic already. The problem is, that DrmCrtc and DrmConnector ask… | |||||
I encountered a second more severe problem when trying it out: drmModeSetCrtc in "drm_output.cpp" expects a pointer to the id of a connector. But until now we use in DrmObject only a getter function for obtaining the object id as a value. We could in general change it for giving back a pointer on the value, but this would circumvent the safeguard of the encapsulation. And we would need to change all calls for it. I really don't think this is proportional to the result: Disposing the two member variables m_crtcId and m_connector in DrmOutput. What do you think? romangg: I encountered a second more severe problem when trying it out: drmModeSetCrtc in "drm_output. | |||||
hmm yes that second problem is more severe. So disposing the two members might be the best idea. graesslin: hmm yes that second problem is more severe. So disposing the two members might be the best idea. | |||||
367 | drmOutput->m_connector = connector->connector_id; | ||||
368 | | ||||
369 | if (m_atomicModeSetting) { | ||||
370 | drmOutput->m_crtc = new DrmCrtc(crtcId, m_fd); | ||||
371 | if (drmOutput->m_crtc->init()) { | ||||
372 | drmOutput->m_crtc->setOutput(drmOutput); | ||||
373 | } else { | ||||
374 | qCWarning(KWIN_DRM) << "Crtc object failed, skipping output on connector" << connector->connector_id; | ||||
375 | delete drmOutput->m_crtc; | ||||
376 | delete drmOutput; | ||||
377 | continue; | ||||
378 | } | ||||
379 | | ||||
380 | drmOutput->m_conn = new DrmConnector(connector->connector_id, m_fd); | ||||
381 | if (drmOutput->m_conn->init()) { | ||||
382 | drmOutput->m_conn->setOutput(drmOutput); | ||||
383 | } else { | ||||
384 | qCWarning(KWIN_DRM) << "Connector object failed, skipping output on connector" << connector->connector_id; | ||||
385 | delete drmOutput->m_conn; | ||||
386 | delete drmOutput; | ||||
387 | continue; | ||||
388 | } | ||||
389 | } | ||||
390 | | ||||
323 | if (crtc->mode_valid) { | 391 | if (crtc->mode_valid) { | ||
324 | drmOutput->m_mode = crtc->mode; | 392 | drmOutput->m_mode = crtc->mode; | ||
325 | } else { | 393 | } else { | ||
326 | drmOutput->m_mode = connector->modes[0]; | 394 | drmOutput->m_mode = connector->modes[0]; | ||
327 | } | 395 | } | ||
328 | drmOutput->m_connector = connector->connector_id; | 396 | qCDebug(KWIN_DRM) << "For new output use mode " << drmOutput->m_mode.name; | ||
397 | | ||||
329 | if (!drmOutput->init(connector.data())) { | 398 | if (!drmOutput->init(connector.data())) { | ||
330 | qCWarning(KWIN_DRM) << "Failed to create output for connector " << connector->connector_id; | 399 | qCWarning(KWIN_DRM) << "Failed to create output for connector " << connector->connector_id; | ||
331 | delete drmOutput; | 400 | delete drmOutput; | ||
332 | continue; | 401 | continue; | ||
333 | } | 402 | } | ||
334 | qCDebug(KWIN_DRM) << "Found new output with uuid" << drmOutput->uuid(); | 403 | qCDebug(KWIN_DRM) << "Found new output with uuid" << drmOutput->uuid(); | ||
335 | connectedOutputs << drmOutput; | 404 | connectedOutputs << drmOutput; | ||
336 | } | 405 | } | ||
▲ Show 20 Lines • Show All 283 Lines • ▼ Show 20 Line(s) | 687 | { | |||
620 | m_buffers << b; | 689 | m_buffers << b; | ||
621 | return b; | 690 | return b; | ||
622 | } | 691 | } | ||
623 | 692 | | |||
624 | DrmBuffer *DrmBackend::createBuffer(gbm_surface *surface) | 693 | DrmBuffer *DrmBackend::createBuffer(gbm_surface *surface) | ||
625 | { | 694 | { | ||
626 | #if HAVE_GBM | 695 | #if HAVE_GBM | ||
627 | DrmBuffer *b = new DrmBuffer(this, surface); | 696 | DrmBuffer *b = new DrmBuffer(this, surface); | ||
697 | b->m_deleteAfterPageFlip = true; | ||||
628 | m_buffers << b; | 698 | m_buffers << b; | ||
629 | return b; | 699 | return b; | ||
630 | #else | 700 | #else | ||
631 | return nullptr; | 701 | return nullptr; | ||
632 | #endif | 702 | #endif | ||
633 | } | 703 | } | ||
634 | 704 | | |||
635 | void DrmBackend::bufferDestroyed(DrmBuffer *b) | 705 | void DrmBackend::bufferDestroyed(DrmBuffer *b) | ||
Show All 18 Lines |
nitpick