File indexing completed on 2025-04-20 10:57:36
0001 /* 0002 * KWin - the KDE window manager 0003 * This file is part of the KDE project. 0004 * 0005 * SPDX-FileCopyrightText: 2021 Xaver Hugl <xaver.hugl@gmail.com> 0006 * 0007 * SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include "drm_buffer.h" 0011 #include "drm_connector.h" 0012 #include "drm_crtc.h" 0013 #include "drm_gpu.h" 0014 #include "drm_layer.h" 0015 #include "drm_logging.h" 0016 #include "drm_pipeline.h" 0017 0018 #include <errno.h> 0019 #include <gbm.h> 0020 0021 namespace KWin 0022 { 0023 0024 DrmPipeline::Error DrmPipeline::presentLegacy() 0025 { 0026 if (!m_pending.crtc->current()) { 0027 Error err = legacyModeset(); 0028 if (err != Error::None) { 0029 return err; 0030 } 0031 } 0032 const auto buffer = m_pending.layer->currentBuffer(); 0033 uint32_t flags = DRM_MODE_PAGE_FLIP_EVENT; 0034 if (m_pending.syncMode == RenderLoopPrivate::SyncMode::Async || m_pending.syncMode == RenderLoopPrivate::SyncMode::AdaptiveAsync) { 0035 flags |= DRM_MODE_PAGE_FLIP_ASYNC; 0036 } 0037 if (drmModePageFlip(gpu()->fd(), m_pending.crtc->id(), buffer->framebufferId(), flags, gpu()) != 0) { 0038 qCWarning(KWIN_DRM) << "Page flip failed:" << strerror(errno); 0039 return errnoToError(); 0040 } 0041 m_pageflipPending = true; 0042 m_pending.crtc->setNext(buffer); 0043 return Error::None; 0044 } 0045 0046 DrmPipeline::Error DrmPipeline::legacyModeset() 0047 { 0048 uint32_t connId = m_connector->id(); 0049 if (!m_pending.layer->checkTestBuffer()) { 0050 return Error::TestBufferFailed; 0051 } 0052 const auto buffer = m_pending.layer->currentBuffer(); 0053 if (drmModeSetCrtc(gpu()->fd(), m_pending.crtc->id(), buffer->framebufferId(), 0, 0, &connId, 1, m_pending.mode->nativeMode()) != 0) { 0054 qCWarning(KWIN_DRM) << "Modeset failed!" << strerror(errno); 0055 return errnoToError(); 0056 } 0057 // make sure the buffer gets kept alive, or the modeset gets reverted by the kernel 0058 if (m_pending.crtc->current()) { 0059 m_pending.crtc->setNext(buffer); 0060 } else { 0061 m_pending.crtc->setCurrent(buffer); 0062 } 0063 return Error::None; 0064 } 0065 0066 DrmPipeline::Error DrmPipeline::commitPipelinesLegacy(const QVector<DrmPipeline *> &pipelines, CommitMode mode) 0067 { 0068 Error err = Error::None; 0069 for (const auto &pipeline : pipelines) { 0070 err = pipeline->applyPendingChangesLegacy(); 0071 if (err != Error::None) { 0072 break; 0073 } 0074 } 0075 if (err != Error::None) { 0076 // at least try to revert the config 0077 for (const auto &pipeline : pipelines) { 0078 pipeline->revertPendingChanges(); 0079 pipeline->applyPendingChangesLegacy(); 0080 } 0081 } else { 0082 for (const auto &pipeline : pipelines) { 0083 pipeline->applyPendingChanges(); 0084 pipeline->m_current = pipeline->m_pending; 0085 if (mode == CommitMode::CommitModeset && pipeline->activePending()) { 0086 pipeline->pageFlipped(std::chrono::steady_clock::now().time_since_epoch()); 0087 } 0088 } 0089 } 0090 return err; 0091 } 0092 0093 DrmPipeline::Error DrmPipeline::applyPendingChangesLegacy() 0094 { 0095 if (!m_pending.active && m_pending.crtc) { 0096 drmModeSetCursor(gpu()->fd(), m_pending.crtc->id(), 0, 0, 0); 0097 } 0098 if (activePending()) { 0099 auto vrr = m_pending.crtc->getProp(DrmCrtc::PropertyIndex::VrrEnabled); 0100 if (vrr && !vrr->setPropertyLegacy(m_pending.syncMode == RenderLoopPrivate::SyncMode::Adaptive || m_pending.syncMode == RenderLoopPrivate::SyncMode::AdaptiveAsync)) { 0101 qCWarning(KWIN_DRM) << "Setting vrr failed!" << strerror(errno); 0102 return errnoToError(); 0103 } 0104 if (const auto &rgbRange = m_connector->getProp(DrmConnector::PropertyIndex::Broadcast_RGB)) { 0105 rgbRange->setEnumLegacy(m_pending.rgbRange); 0106 } 0107 if (const auto overscan = m_connector->getProp(DrmConnector::PropertyIndex::Overscan)) { 0108 overscan->setPropertyLegacy(m_pending.overscan); 0109 } else if (const auto underscan = m_connector->getProp(DrmConnector::PropertyIndex::Underscan)) { 0110 const uint32_t hborder = calculateUnderscan(); 0111 underscan->setEnumLegacy(m_pending.overscan != 0 ? DrmConnector::UnderscanOptions::On : DrmConnector::UnderscanOptions::Off); 0112 m_connector->getProp(DrmConnector::PropertyIndex::Underscan_vborder)->setPropertyLegacy(m_pending.overscan); 0113 m_connector->getProp(DrmConnector::PropertyIndex::Underscan_hborder)->setPropertyLegacy(hborder); 0114 } 0115 if (const auto scaling = m_connector->getProp(DrmConnector::PropertyIndex::ScalingMode); scaling && scaling->hasEnum(DrmConnector::ScalingMode::None)) { 0116 scaling->setEnumLegacy(DrmConnector::ScalingMode::None); 0117 } 0118 if (m_pending.crtc != m_current.crtc || m_pending.mode != m_current.mode) { 0119 Error err = legacyModeset(); 0120 if (err != Error::None) { 0121 return err; 0122 } 0123 } 0124 if (m_pending.gamma && drmModeCrtcSetGamma(gpu()->fd(), m_pending.crtc->id(), m_pending.gamma->lut().size(), m_pending.gamma->lut().red(), m_pending.gamma->lut().green(), m_pending.gamma->lut().blue()) != 0) { 0125 qCWarning(KWIN_DRM) << "Setting gamma failed!" << strerror(errno); 0126 return errnoToError(); 0127 } 0128 if (const auto contentType = m_connector->getProp(DrmConnector::PropertyIndex::ContentType)) { 0129 contentType->setEnumLegacy(m_pending.contentType); 0130 } 0131 setCursorLegacy(); 0132 moveCursorLegacy(); 0133 } 0134 if (!m_connector->getProp(DrmConnector::PropertyIndex::Dpms)->setPropertyLegacy(activePending() ? DRM_MODE_DPMS_ON : DRM_MODE_DPMS_OFF)) { 0135 qCWarning(KWIN_DRM) << "Setting legacy dpms failed!" << strerror(errno); 0136 return errnoToError(); 0137 } 0138 return Error::None; 0139 } 0140 0141 bool DrmPipeline::setCursorLegacy() 0142 { 0143 const auto bo = cursorLayer()->currentBuffer(); 0144 const uint32_t handle = bo && bo->buffer() && cursorLayer()->isVisible() ? bo->buffer()->handles()[0] : 0; 0145 0146 struct drm_mode_cursor2 arg = { 0147 .flags = DRM_MODE_CURSOR_BO | DRM_MODE_CURSOR_MOVE, 0148 .crtc_id = m_pending.crtc->id(), 0149 .x = m_pending.cursorLayer->position().x(), 0150 .y = m_pending.cursorLayer->position().y(), 0151 .width = (uint32_t)gpu()->cursorSize().width(), 0152 .height = (uint32_t)gpu()->cursorSize().height(), 0153 .handle = handle, 0154 .hot_x = m_pending.cursorHotspot.x(), 0155 .hot_y = m_pending.cursorHotspot.y(), 0156 }; 0157 return drmIoctl(gpu()->fd(), DRM_IOCTL_MODE_CURSOR2, &arg) == 0; 0158 } 0159 0160 bool DrmPipeline::moveCursorLegacy() 0161 { 0162 return drmModeMoveCursor(gpu()->fd(), m_pending.crtc->id(), cursorLayer()->position().x(), cursorLayer()->position().y()) == 0; 0163 } 0164 0165 }