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: 2016 Roman Gilg <subdiff@gmail.com>
0006     SPDX-FileCopyrightText: 2022 Xaver Hugl <xaver.hugl@gmail.com>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 #include "drm_plane.h"
0011 
0012 #include "config-kwin.h"
0013 
0014 #include "drm_buffer.h"
0015 #include "drm_gpu.h"
0016 #include "drm_logging.h"
0017 #include "drm_pointer.h"
0018 
0019 #include <drm_fourcc.h>
0020 
0021 namespace KWin
0022 {
0023 
0024 DrmPlane::DrmPlane(DrmGpu *gpu, uint32_t planeId)
0025     : DrmObject(gpu, planeId, {
0026                                   PropertyDefinition(QByteArrayLiteral("type"), Requirement::Required, {QByteArrayLiteral("Overlay"), QByteArrayLiteral("Primary"), QByteArrayLiteral("Cursor")}),
0027                                   PropertyDefinition(QByteArrayLiteral("SRC_X"), Requirement::Required),
0028                                   PropertyDefinition(QByteArrayLiteral("SRC_Y"), Requirement::Required),
0029                                   PropertyDefinition(QByteArrayLiteral("SRC_W"), Requirement::Required),
0030                                   PropertyDefinition(QByteArrayLiteral("SRC_H"), Requirement::Required),
0031                                   PropertyDefinition(QByteArrayLiteral("CRTC_X"), Requirement::Required),
0032                                   PropertyDefinition(QByteArrayLiteral("CRTC_Y"), Requirement::Required),
0033                                   PropertyDefinition(QByteArrayLiteral("CRTC_W"), Requirement::Required),
0034                                   PropertyDefinition(QByteArrayLiteral("CRTC_H"), Requirement::Required),
0035                                   PropertyDefinition(QByteArrayLiteral("FB_ID"), Requirement::Required),
0036                                   PropertyDefinition(QByteArrayLiteral("CRTC_ID"), Requirement::Required),
0037                                   PropertyDefinition(QByteArrayLiteral("rotation"), Requirement::Optional, {QByteArrayLiteral("rotate-0"), QByteArrayLiteral("rotate-90"), QByteArrayLiteral("rotate-180"), QByteArrayLiteral("rotate-270"), QByteArrayLiteral("reflect-x"), QByteArrayLiteral("reflect-y")}),
0038                                   PropertyDefinition(QByteArrayLiteral("IN_FORMATS"), Requirement::Optional),
0039                               },
0040                 DRM_MODE_OBJECT_PLANE)
0041 {
0042 }
0043 
0044 bool DrmPlane::init()
0045 {
0046     DrmUniquePtr<drmModePlane> p(drmModeGetPlane(gpu()->fd(), id()));
0047 
0048     if (!p) {
0049         qCWarning(KWIN_DRM) << "Failed to get kernel plane" << id();
0050         return false;
0051     }
0052 
0053     m_possibleCrtcs = p->possible_crtcs;
0054 
0055     bool success = initProps();
0056     if (success) {
0057         if (const auto prop = getProp(PropertyIndex::Rotation)) {
0058             m_supportedTransformations = Transformations();
0059             auto checkSupport = [this, prop](Transformation t) {
0060                 if (prop->hasEnum(t)) {
0061                     m_supportedTransformations |= t;
0062                 }
0063             };
0064             checkSupport(Transformation::Rotate0);
0065             checkSupport(Transformation::Rotate90);
0066             checkSupport(Transformation::Rotate180);
0067             checkSupport(Transformation::Rotate270);
0068             checkSupport(Transformation::ReflectX);
0069             checkSupport(Transformation::ReflectY);
0070         } else {
0071             m_supportedTransformations = Transformation::Rotate0;
0072         }
0073 
0074         // read formats from blob if available and if modifiers are supported, and from the plane object if not
0075         if (const auto formatProp = getProp(PropertyIndex::In_Formats); formatProp && formatProp->immutableBlob() && gpu()->addFB2ModifiersSupported()) {
0076             drmModeFormatModifierIterator iterator{};
0077             while (drmModeFormatModifierBlobIterNext(formatProp->immutableBlob(), &iterator)) {
0078                 m_supportedFormats[iterator.fmt].push_back(iterator.mod);
0079             }
0080         } else {
0081             for (uint32_t i = 0; i < p->count_formats; i++) {
0082                 m_supportedFormats.insert(p->formats[i], {DRM_FORMAT_MOD_LINEAR});
0083             }
0084         }
0085         if (m_supportedFormats.isEmpty()) {
0086             qCWarning(KWIN_DRM) << "Driver doesn't advertise any formats for this plane. Falling back to XRGB8888 without explicit modifiers";
0087             m_supportedFormats.insert(DRM_FORMAT_XRGB8888, {});
0088         }
0089     }
0090     return success;
0091 }
0092 
0093 DrmPlane::TypeIndex DrmPlane::type() const
0094 {
0095     const auto &prop = getProp(PropertyIndex::Type);
0096     return prop->enumForValue<DrmPlane::TypeIndex>(prop->current());
0097 }
0098 
0099 void DrmPlane::setNext(const std::shared_ptr<DrmFramebuffer> &b)
0100 {
0101     m_next = b;
0102 }
0103 
0104 DrmPlane::Transformations DrmPlane::transformation()
0105 {
0106     if (auto property = getProp(PropertyIndex::Rotation)) {
0107         return Transformations(static_cast<uint32_t>(property->pending()));
0108     }
0109     return Transformations(Transformation::Rotate0);
0110 }
0111 
0112 void DrmPlane::flipBuffer()
0113 {
0114     m_current = m_next;
0115     m_next = nullptr;
0116 }
0117 
0118 void DrmPlane::set(const QPoint &srcPos, const QSize &srcSize, const QRect &dst)
0119 {
0120     // Src* are in 16.16 fixed point format
0121     setPending(PropertyIndex::SrcX, srcPos.x() << 16);
0122     setPending(PropertyIndex::SrcY, srcPos.y() << 16);
0123     setPending(PropertyIndex::SrcW, srcSize.width() << 16);
0124     setPending(PropertyIndex::SrcH, srcSize.height() << 16);
0125     setPending(PropertyIndex::CrtcX, dst.x());
0126     setPending(PropertyIndex::CrtcY, dst.y());
0127     setPending(PropertyIndex::CrtcW, dst.width());
0128     setPending(PropertyIndex::CrtcH, dst.height());
0129 }
0130 
0131 void DrmPlane::setBuffer(DrmFramebuffer *buffer)
0132 {
0133     setPending(PropertyIndex::FbId, buffer ? buffer->framebufferId() : 0);
0134 }
0135 
0136 bool DrmPlane::isCrtcSupported(int pipeIndex) const
0137 {
0138     return (m_possibleCrtcs & (1 << pipeIndex));
0139 }
0140 
0141 QMap<uint32_t, QVector<uint64_t>> DrmPlane::formats() const
0142 {
0143     return m_supportedFormats;
0144 }
0145 
0146 std::shared_ptr<DrmFramebuffer> DrmPlane::current() const
0147 {
0148     return m_current;
0149 }
0150 
0151 std::shared_ptr<DrmFramebuffer> DrmPlane::next() const
0152 {
0153     return m_next;
0154 }
0155 
0156 void DrmPlane::setCurrent(const std::shared_ptr<DrmFramebuffer> &b)
0157 {
0158     m_current = b;
0159 }
0160 
0161 DrmPlane::Transformations DrmPlane::supportedTransformations() const
0162 {
0163     return m_supportedTransformations;
0164 }
0165 
0166 void DrmPlane::disable()
0167 {
0168     setPending(PropertyIndex::CrtcId, 0);
0169     setPending(PropertyIndex::FbId, 0);
0170     m_next = nullptr;
0171 }
0172 
0173 void DrmPlane::releaseBuffers()
0174 {
0175     if (m_next) {
0176         m_next->releaseBuffer();
0177     }
0178     if (m_current) {
0179         m_current->releaseBuffer();
0180     }
0181 }
0182 }