KWin
Loading...
Searching...
No Matches
drm_pipeline_legacy.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: 2021 Xaver Hugl <xaver.hugl@gmail.com>
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10#include "core/graphicsbuffer.h"
11#include "drm_buffer.h"
12#include "drm_commit.h"
13#include "drm_commit_thread.h"
14#include "drm_connector.h"
15#include "drm_crtc.h"
16#include "drm_gpu.h"
17#include "drm_layer.h"
18#include "drm_logging.h"
19#include "drm_pipeline.h"
20
21#include <errno.h>
22#include <gbm.h>
23
24namespace KWin
25{
26
27DrmPipeline::Error DrmPipeline::presentLegacy()
28{
29 if (Error err = applyPendingChangesLegacy(); err != Error::None) {
30 return err;
31 }
32 const auto buffer = m_primaryLayer->currentBuffer();
33 auto commit = std::make_unique<DrmLegacyCommit>(this, buffer);
34 if (!commit->doPageflip(m_pending.presentationMode)) {
35 qCWarning(KWIN_DRM) << "Page flip failed:" << strerror(errno);
36 return errnoToError();
37 }
38 m_commitThread->setPendingCommit(std::move(commit));
39 return Error::None;
40}
41
43{
44 legacyModeset();
45}
46
47DrmPipeline::Error DrmPipeline::legacyModeset()
48{
49 if (!m_primaryLayer->checkTestBuffer()) {
51 }
52 auto commit = std::make_unique<DrmLegacyCommit>(this, m_primaryLayer->currentBuffer());
53 if (!commit->doModeset(m_connector, m_pending.mode.get())) {
54 qCWarning(KWIN_DRM) << "Modeset failed!" << strerror(errno);
55 return errnoToError();
56 }
57 return Error::None;
58}
59
60DrmPipeline::Error DrmPipeline::commitPipelinesLegacy(const QList<DrmPipeline *> &pipelines, CommitMode mode, const QList<DrmObject *> &unusedObjects)
61{
62 Error err = Error::None;
63 for (const auto &pipeline : pipelines) {
64 err = pipeline->applyPendingChangesLegacy();
65 if (err != Error::None) {
66 break;
67 }
68 }
69 if (err != Error::None) {
70 // at least try to revert the config
71 for (const auto &pipeline : pipelines) {
72 pipeline->revertPendingChanges();
73 pipeline->applyPendingChangesLegacy();
74 }
75 } else {
76 for (const auto &pipeline : pipelines) {
77 pipeline->applyPendingChanges();
78 if (mode == CommitMode::CommitModeset && pipeline->activePending()) {
79 pipeline->pageFlipped(std::chrono::steady_clock::now().time_since_epoch(), PageflipType::Normal, PresentationMode::VSync);
80 }
81 }
82 for (const auto &obj : unusedObjects) {
83 if (auto crtc = dynamic_cast<DrmCrtc *>(obj)) {
84 drmModeSetCrtc(pipelines.front()->gpu()->fd(), crtc->id(), 0, 0, 0, nullptr, 0, nullptr);
85 }
86 }
87 }
88 return err;
89}
90
91DrmPipeline::Error DrmPipeline::applyPendingChangesLegacy()
92{
93 if (!m_pending.active && m_pending.crtc) {
94 drmModeSetCursor(gpu()->fd(), m_pending.crtc->id(), 0, 0, 0);
95 }
96 if (activePending()) {
97 const bool shouldEnableVrr = m_pending.presentationMode == PresentationMode::AdaptiveSync || m_pending.presentationMode == PresentationMode::AdaptiveAsync;
98 if (m_pending.crtc->vrrEnabled.isValid() && !m_pending.crtc->vrrEnabled.setPropertyLegacy(shouldEnableVrr)) {
99 qCWarning(KWIN_DRM) << "Setting vrr failed!" << strerror(errno);
100 return errnoToError();
101 }
102 if (m_connector->broadcastRGB.isValid()) {
103 m_connector->broadcastRGB.setEnumLegacy(DrmConnector::rgbRangeToBroadcastRgb(m_pending.rgbRange));
104 }
105 if (m_connector->overscan.isValid()) {
106 m_connector->overscan.setPropertyLegacy(m_pending.overscan);
107 } else if (m_connector->underscan.isValid()) {
108 const uint32_t hborder = calculateUnderscan();
109 m_connector->underscan.setEnumLegacy(m_pending.overscan != 0 ? DrmConnector::UnderscanOptions::On : DrmConnector::UnderscanOptions::Off);
110 m_connector->underscanVBorder.setPropertyLegacy(m_pending.overscan);
111 m_connector->underscanHBorder.setPropertyLegacy(hborder);
112 }
113 if (m_connector->scalingMode.isValid() && m_connector->scalingMode.hasEnum(DrmConnector::ScalingMode::None)) {
115 }
116 if (m_connector->hdrMetadata.isValid()) {
117 const auto blob = createHdrMetadata(m_pending.colorDescription.transferFunction());
118 m_connector->hdrMetadata.setPropertyLegacy(blob ? blob->blobId() : 0);
119 }
120 if (m_connector->colorspace.isValid()) {
121 if (m_pending.colorDescription.colorimetry() == NamedColorimetry::BT2020) {
123 } else {
125 }
126 }
127 const auto currentModeContent = m_pending.crtc->queryCurrentMode();
128 if (m_pending.crtc != m_next.crtc || *m_pending.mode != currentModeContent) {
129 qCDebug(KWIN_DRM) << "Using legacy path to set mode" << m_pending.mode->nativeMode()->name;
130 Error err = legacyModeset();
131 if (err != Error::None) {
132 return err;
133 }
134 }
135 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) {
136 qCWarning(KWIN_DRM) << "Setting gamma failed!" << strerror(errno);
137 return errnoToError();
138 }
139 if (m_connector->contentType.isValid()) {
140 m_connector->contentType.setEnumLegacy(m_pending.contentType);
141 }
142 setCursorLegacy();
143 }
144 if (!m_connector->dpms.setPropertyLegacy(activePending() ? DRM_MODE_DPMS_ON : DRM_MODE_DPMS_OFF)) {
145 qCWarning(KWIN_DRM) << "Setting legacy dpms failed!" << strerror(errno);
146 return errnoToError();
147 }
148 return Error::None;
149}
150
151bool DrmPipeline::setCursorLegacy()
152{
153 const auto bo = cursorLayer()->currentBuffer();
154 uint32_t handle = 0;
155 if (bo && bo->buffer() && cursorLayer()->isEnabled()) {
156 const DmaBufAttributes *attributes = bo->buffer()->dmabufAttributes();
157 if (drmPrimeFDToHandle(gpu()->fd(), attributes->fd[0].get(), &handle) != 0) {
158 qCWarning(KWIN_DRM) << "drmPrimeFDToHandle() failed";
159 return false;
160 }
161 }
162
163 struct drm_mode_cursor2 arg = {
164 .flags = DRM_MODE_CURSOR_BO | DRM_MODE_CURSOR_MOVE,
165 .crtc_id = m_pending.crtc->id(),
166 .x = int32_t(m_cursorLayer->position().x()),
167 .y = int32_t(m_cursorLayer->position().y()),
168 .width = (uint32_t)gpu()->cursorSize().width(),
169 .height = (uint32_t)gpu()->cursorSize().height(),
170 .handle = handle,
171 .hot_x = int32_t(m_cursorLayer->hotspot().x()),
172 .hot_y = int32_t(m_cursorLayer->hotspot().y()),
173 };
174 const int ret = drmIoctl(gpu()->fd(), DRM_IOCTL_MODE_CURSOR2, &arg);
175
176 if (handle != 0) {
177 drmCloseBufferHandle(gpu()->fd(), handle);
178 }
179 return ret == 0;
180}
181}
NamedTransferFunction transferFunction() const
const Colorimetry & colorimetry() const
DrmEnumProperty< BroadcastRgbOptions > broadcastRGB
DrmProperty underscanHBorder
static BroadcastRgbOptions rgbRangeToBroadcastRgb(Output::RgbRange rgbRange)
DrmEnumProperty< DrmContentType > contentType
DrmEnumProperty< ScalingMode > scalingMode
DrmProperty hdrMetadata
DrmEnumProperty< Colorspace > colorspace
DrmProperty underscanVBorder
DrmEnumProperty< UnderscanOptions > underscan
DrmProperty vrrEnabled
Definition drm_crtc.h:45
drmModeModeInfo queryCurrentMode()
Definition drm_crtc.cpp:55
bool setEnumLegacy(Enum value)
bool hasEnum(Enum value) const
int fd() const
Definition drm_gpu.cpp:648
QSize cursorSize() const
Definition drm_gpu.cpp:801
uint32_t id() const
DrmPipelineLayer * cursorLayer() const
DrmGpu * gpu() const
DrmCrtc * crtc() const
std::shared_ptr< DrmConnectorMode > mode() const
bool activePending() const
virtual std::shared_ptr< DrmFramebuffer > currentBuffer() const =0
bool setPropertyLegacy(uint64_t value)
bool isValid() const
int drmModeCrtcSetGamma(int fd, uint32_t crtc_id, uint32_t size, uint16_t *red, uint16_t *green, uint16_t *blue)
Definition mock_drm.cpp:667
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 drmModeSetCursor(int fd, uint32_t crtcId, uint32_t bo_handle, uint32_t width, uint32_t height)
Definition mock_drm.cpp:562