File indexing completed on 2026-03-08 12:24:31

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 #pragma once
0011 
0012 #include <QPoint>
0013 #include <QSize>
0014 #include <QVector>
0015 
0016 #include <chrono>
0017 #include <xf86drmMode.h>
0018 
0019 #include "core/colorlut.h"
0020 #include "core/output.h"
0021 #include "core/renderloop_p.h"
0022 #include "drm_connector.h"
0023 #include "drm_plane.h"
0024 
0025 namespace KWin
0026 {
0027 
0028 class DrmGpu;
0029 class DrmConnector;
0030 class DrmCrtc;
0031 class GammaRamp;
0032 class DrmConnectorMode;
0033 class DrmPipelineLayer;
0034 class DrmOverlayLayer;
0035 
0036 class DrmGammaRamp
0037 {
0038 public:
0039     DrmGammaRamp(DrmCrtc *crtc, const std::shared_ptr<ColorTransformation> &transformation);
0040     ~DrmGammaRamp();
0041 
0042     const ColorLUT &lut() const;
0043     uint32_t blobId() const;
0044 
0045 private:
0046     DrmGpu *m_gpu;
0047     const ColorLUT m_lut;
0048     uint32_t m_blobId = 0;
0049 };
0050 
0051 class DrmCTM
0052 {
0053 public:
0054     DrmCTM(DrmGpu *gpu, const QMatrix3x3 &ctm);
0055     ~DrmCTM();
0056 
0057     uint32_t blobId() const;
0058 
0059 private:
0060     DrmGpu *const m_gpu;
0061     uint32_t m_blobId = 0;
0062 };
0063 
0064 class DrmPipeline
0065 {
0066 public:
0067     DrmPipeline(DrmConnector *conn);
0068     ~DrmPipeline();
0069 
0070     enum class Error {
0071         None,
0072         OutofMemory,
0073         InvalidArguments,
0074         NoPermission,
0075         FramePending,
0076         TestBufferFailed,
0077         Unknown,
0078     };
0079     Q_ENUM(Error)
0080 
0081     /**
0082      * tests the pending commit first and commits it if the test passes
0083      * if the test fails, there is a guarantee for no lasting changes
0084      */
0085     Error present();
0086     bool testScanout();
0087     bool maybeModeset();
0088 
0089     bool needsModeset() const;
0090     void applyPendingChanges();
0091     void revertPendingChanges();
0092 
0093     bool setCursor(const QPoint &hotspot = QPoint());
0094     bool moveCursor();
0095 
0096     DrmConnector *connector() const;
0097     DrmCrtc *currentCrtc() const;
0098     DrmGpu *gpu() const;
0099 
0100     void pageFlipped(std::chrono::nanoseconds timestamp);
0101     bool pageflipPending() const;
0102     bool modesetPresentPending() const;
0103     void resetModesetPresentPending();
0104     void printDebugInfo() const;
0105     /**
0106      * what size buffers submitted to this pipeline should have
0107      */
0108     QSize bufferSize() const;
0109 
0110     QMap<uint32_t, QVector<uint64_t>> formats() const;
0111     QMap<uint32_t, QVector<uint64_t>> cursorFormats() const;
0112     bool pruneModifier();
0113 
0114     void setOutput(DrmOutput *output);
0115     DrmOutput *output() const;
0116 
0117     DrmCrtc *crtc() const;
0118     std::shared_ptr<DrmConnectorMode> mode() const;
0119     bool active() const;
0120     bool activePending() const;
0121     bool enabled() const;
0122     DrmPipelineLayer *primaryLayer() const;
0123     DrmOverlayLayer *cursorLayer() const;
0124     DrmPlane::Transformations renderOrientation() const;
0125     DrmPlane::Transformations bufferOrientation() const;
0126     RenderLoopPrivate::SyncMode syncMode() const;
0127     uint32_t overscan() const;
0128     Output::RgbRange rgbRange() const;
0129     DrmConnector::DrmContentType contentType() const;
0130 
0131     void setCrtc(DrmCrtc *crtc);
0132     void setMode(const std::shared_ptr<DrmConnectorMode> &mode);
0133     void setActive(bool active);
0134     void setEnable(bool enable);
0135     void setLayers(const std::shared_ptr<DrmPipelineLayer> &primaryLayer, const std::shared_ptr<DrmOverlayLayer> &cursorLayer);
0136     void setRenderOrientation(DrmPlane::Transformations orientation);
0137     void setBufferOrientation(DrmPlane::Transformations orientation);
0138     void setSyncMode(RenderLoopPrivate::SyncMode mode);
0139     void setOverscan(uint32_t overscan);
0140     void setRgbRange(Output::RgbRange range);
0141     void setGammaRamp(const std::shared_ptr<ColorTransformation> &transformation);
0142     void setCTM(const QMatrix3x3 &ctm);
0143     void setContentType(DrmConnector::DrmContentType type);
0144 
0145     enum class CommitMode {
0146         Test,
0147         TestAllowModeset,
0148         Commit,
0149         CommitModeset
0150     };
0151     Q_ENUM(CommitMode)
0152     static Error commitPipelines(const QVector<DrmPipeline *> &pipelines, CommitMode mode, const QVector<DrmObject *> &unusedObjects = {});
0153 
0154 private:
0155     bool isBufferForDirectScanout() const;
0156     uint32_t calculateUnderscan();
0157     static Error errnoToError();
0158     void checkHardwareRotation();
0159 
0160     // legacy only
0161     Error presentLegacy();
0162     Error legacyModeset();
0163     Error applyPendingChangesLegacy();
0164     bool setCursorLegacy();
0165     bool moveCursorLegacy();
0166     static Error commitPipelinesLegacy(const QVector<DrmPipeline *> &pipelines, CommitMode mode);
0167 
0168     // atomic modesetting only
0169     bool populateAtomicValues(drmModeAtomicReq *req);
0170     void atomicCommitFailed();
0171     void atomicTestSuccessful();
0172     void atomicCommitSuccessful();
0173     void atomicModesetSuccessful();
0174     void prepareAtomicModeset();
0175     bool prepareAtomicPresentation();
0176     void prepareAtomicDisable();
0177     static Error commitPipelinesAtomic(const QVector<DrmPipeline *> &pipelines, CommitMode mode, const QVector<DrmObject *> &unusedObjects);
0178 
0179     // logging helpers
0180     enum class PrintMode {
0181         OnlyChanged,
0182         All,
0183     };
0184     static void printFlags(uint32_t flags);
0185 
0186     DrmOutput *m_output = nullptr;
0187     DrmConnector *m_connector = nullptr;
0188 
0189     bool m_pageflipPending = false;
0190     bool m_modesetPresentPending = false;
0191 
0192     struct State
0193     {
0194         DrmCrtc *crtc = nullptr;
0195         QMap<uint32_t, QVector<uint64_t>> formats;
0196         bool active = true; // whether or not the pipeline should be currently used
0197         bool enabled = true; // whether or not the pipeline needs a crtc
0198         bool needsModeset = false;
0199         std::shared_ptr<DrmConnectorMode> mode;
0200         uint32_t overscan = 0;
0201         Output::RgbRange rgbRange = Output::RgbRange::Automatic;
0202         RenderLoopPrivate::SyncMode syncMode = RenderLoopPrivate::SyncMode::Fixed;
0203         std::shared_ptr<ColorTransformation> colorTransformation;
0204         std::shared_ptr<DrmGammaRamp> gamma;
0205         std::shared_ptr<DrmCTM> ctm;
0206         DrmConnector::DrmContentType contentType = DrmConnector::DrmContentType::Graphics;
0207 
0208         std::shared_ptr<DrmPipelineLayer> layer;
0209         std::shared_ptr<DrmOverlayLayer> cursorLayer;
0210         QPoint cursorHotspot;
0211 
0212         // the transformation that this pipeline will apply to submitted buffers
0213         DrmPlane::Transformations bufferOrientation = DrmPlane::Transformation::Rotate0;
0214         // the transformation that buffers submitted to the pipeline should have
0215         DrmPlane::Transformations renderOrientation = DrmPlane::Transformation::Rotate0;
0216     };
0217     // the state that is to be tested next
0218     State m_pending;
0219     // the state that will be applied at the next real atomic commit
0220     State m_next;
0221     // the state that is already committed
0222     State m_current;
0223 };
0224 
0225 }