File indexing completed on 2024-11-10 04:56:30
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 "core/graphicsbuffer.h" 0011 #include "drm_buffer.h" 0012 #include "drm_commit.h" 0013 #include "drm_commit_thread.h" 0014 #include "drm_connector.h" 0015 #include "drm_crtc.h" 0016 #include "drm_gpu.h" 0017 #include "drm_layer.h" 0018 #include "drm_logging.h" 0019 #include "drm_pipeline.h" 0020 0021 #include <errno.h> 0022 #include <gbm.h> 0023 0024 namespace KWin 0025 { 0026 0027 DrmPipeline::Error DrmPipeline::presentLegacy() 0028 { 0029 if (Error err = applyPendingChangesLegacy(); err != Error::None) { 0030 return err; 0031 } 0032 const auto buffer = m_primaryLayer->currentBuffer(); 0033 auto commit = std::make_unique<DrmLegacyCommit>(this, buffer); 0034 if (!commit->doPageflip(m_pending.presentationMode)) { 0035 qCWarning(KWIN_DRM) << "Page flip failed:" << strerror(errno); 0036 return errnoToError(); 0037 } 0038 m_commitThread->setPendingCommit(std::move(commit)); 0039 return Error::None; 0040 } 0041 0042 void DrmPipeline::forceLegacyModeset() 0043 { 0044 legacyModeset(); 0045 } 0046 0047 DrmPipeline::Error DrmPipeline::legacyModeset() 0048 { 0049 if (!m_primaryLayer->checkTestBuffer()) { 0050 return Error::TestBufferFailed; 0051 } 0052 auto commit = std::make_unique<DrmLegacyCommit>(this, m_primaryLayer->currentBuffer()); 0053 if (!commit->doModeset(m_connector, m_pending.mode.get())) { 0054 qCWarning(KWIN_DRM) << "Modeset failed!" << strerror(errno); 0055 return errnoToError(); 0056 } 0057 return Error::None; 0058 } 0059 0060 DrmPipeline::Error DrmPipeline::commitPipelinesLegacy(const QList<DrmPipeline *> &pipelines, CommitMode mode) 0061 { 0062 Error err = Error::None; 0063 for (const auto &pipeline : pipelines) { 0064 err = pipeline->applyPendingChangesLegacy(); 0065 if (err != Error::None) { 0066 break; 0067 } 0068 } 0069 if (err != Error::None) { 0070 // at least try to revert the config 0071 for (const auto &pipeline : pipelines) { 0072 pipeline->revertPendingChanges(); 0073 pipeline->applyPendingChangesLegacy(); 0074 } 0075 } else { 0076 for (const auto &pipeline : pipelines) { 0077 pipeline->applyPendingChanges(); 0078 if (mode == CommitMode::CommitModeset && pipeline->activePending()) { 0079 pipeline->pageFlipped(std::chrono::steady_clock::now().time_since_epoch(), PageflipType::Normal, PresentationMode::VSync); 0080 } 0081 } 0082 } 0083 return err; 0084 } 0085 0086 DrmPipeline::Error DrmPipeline::applyPendingChangesLegacy() 0087 { 0088 if (!m_pending.active && m_pending.crtc) { 0089 drmModeSetCursor(gpu()->fd(), m_pending.crtc->id(), 0, 0, 0); 0090 } 0091 if (activePending()) { 0092 const bool shouldEnableVrr = m_pending.presentationMode == PresentationMode::AdaptiveSync || m_pending.presentationMode == PresentationMode::AdaptiveAsync; 0093 if (m_pending.crtc->vrrEnabled.isValid() && !m_pending.crtc->vrrEnabled.setPropertyLegacy(shouldEnableVrr)) { 0094 qCWarning(KWIN_DRM) << "Setting vrr failed!" << strerror(errno); 0095 return errnoToError(); 0096 } 0097 if (m_connector->broadcastRGB.isValid()) { 0098 m_connector->broadcastRGB.setEnumLegacy(DrmConnector::rgbRangeToBroadcastRgb(m_pending.rgbRange)); 0099 } 0100 if (m_connector->overscan.isValid()) { 0101 m_connector->overscan.setPropertyLegacy(m_pending.overscan); 0102 } else if (m_connector->underscan.isValid()) { 0103 const uint32_t hborder = calculateUnderscan(); 0104 m_connector->underscan.setEnumLegacy(m_pending.overscan != 0 ? DrmConnector::UnderscanOptions::On : DrmConnector::UnderscanOptions::Off); 0105 m_connector->underscanVBorder.setPropertyLegacy(m_pending.overscan); 0106 m_connector->underscanHBorder.setPropertyLegacy(hborder); 0107 } 0108 if (m_connector->scalingMode.isValid() && m_connector->scalingMode.hasEnum(DrmConnector::ScalingMode::None)) { 0109 m_connector->scalingMode.setEnumLegacy(DrmConnector::ScalingMode::None); 0110 } 0111 const auto currentModeContent = m_pending.crtc->queryCurrentMode(); 0112 if (m_pending.crtc != m_next.crtc || *m_pending.mode != currentModeContent) { 0113 qCDebug(KWIN_DRM) << "Using legacy path to set mode" << m_pending.mode->nativeMode()->name; 0114 Error err = legacyModeset(); 0115 if (err != Error::None) { 0116 return err; 0117 } 0118 } 0119 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) { 0120 qCWarning(KWIN_DRM) << "Setting gamma failed!" << strerror(errno); 0121 return errnoToError(); 0122 } 0123 if (m_connector->contentType.isValid()) { 0124 m_connector->contentType.setEnumLegacy(m_pending.contentType); 0125 } 0126 setCursorLegacy(); 0127 } 0128 if (!m_connector->dpms.setPropertyLegacy(activePending() ? DRM_MODE_DPMS_ON : DRM_MODE_DPMS_OFF)) { 0129 qCWarning(KWIN_DRM) << "Setting legacy dpms failed!" << strerror(errno); 0130 return errnoToError(); 0131 } 0132 return Error::None; 0133 } 0134 0135 bool DrmPipeline::setCursorLegacy() 0136 { 0137 const auto bo = cursorLayer()->currentBuffer(); 0138 uint32_t handle = 0; 0139 if (bo && bo->buffer() && cursorLayer()->isEnabled()) { 0140 const DmaBufAttributes *attributes = bo->buffer()->dmabufAttributes(); 0141 if (drmPrimeFDToHandle(gpu()->fd(), attributes->fd[0].get(), &handle) != 0) { 0142 qCWarning(KWIN_DRM) << "drmPrimeFDToHandle() failed"; 0143 return false; 0144 } 0145 } 0146 0147 struct drm_mode_cursor2 arg = { 0148 .flags = DRM_MODE_CURSOR_BO | DRM_MODE_CURSOR_MOVE, 0149 .crtc_id = m_pending.crtc->id(), 0150 .x = int32_t(m_cursorLayer->position().x()), 0151 .y = int32_t(m_cursorLayer->position().y()), 0152 .width = (uint32_t)gpu()->cursorSize().width(), 0153 .height = (uint32_t)gpu()->cursorSize().height(), 0154 .handle = handle, 0155 .hot_x = int32_t(m_cursorLayer->hotspot().x()), 0156 .hot_y = int32_t(m_cursorLayer->hotspot().y()), 0157 }; 0158 const int ret = drmIoctl(gpu()->fd(), DRM_IOCTL_MODE_CURSOR2, &arg); 0159 0160 if (handle != 0) { 0161 drmCloseBufferHandle(gpu()->fd(), handle); 0162 } 0163 return ret == 0; 0164 } 0165 }