File indexing completed on 2024-06-23 05:25:13

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 <QList>
0013 #include <QPoint>
0014 #include <QSize>
0015 
0016 #include <chrono>
0017 #include <xf86drmMode.h>
0018 
0019 #include "core/colorlut.h"
0020 #include "core/colorspace.h"
0021 #include "core/output.h"
0022 #include "core/renderloop_p.h"
0023 #include "drm_blob.h"
0024 #include "drm_connector.h"
0025 #include "drm_plane.h"
0026 
0027 namespace KWin
0028 {
0029 
0030 class DrmGpu;
0031 class DrmConnector;
0032 class DrmCrtc;
0033 class GammaRamp;
0034 class DrmConnectorMode;
0035 class DrmPipelineLayer;
0036 class DrmCommitThread;
0037 
0038 class DrmGammaRamp
0039 {
0040 public:
0041     DrmGammaRamp(DrmCrtc *crtc, const std::shared_ptr<ColorTransformation> &transformation);
0042 
0043     const ColorLUT &lut() const;
0044     std::shared_ptr<DrmBlob> blob() const;
0045 
0046 private:
0047     const ColorLUT m_lut;
0048     std::shared_ptr<DrmBlob> m_blob;
0049 };
0050 
0051 class DrmPipeline
0052 {
0053 public:
0054     DrmPipeline(DrmConnector *conn);
0055     ~DrmPipeline();
0056 
0057     enum class Error {
0058         None,
0059         OutofMemory,
0060         InvalidArguments,
0061         NoPermission,
0062         FramePending,
0063         TestBufferFailed,
0064         Unknown,
0065     };
0066     Q_ENUM(Error)
0067 
0068     /**
0069      * tests the pending commit first and commits it if the test passes
0070      * if the test fails, there is a guarantee for no lasting changes
0071      */
0072     Error present();
0073     bool testScanout();
0074     bool maybeModeset();
0075     void forceLegacyModeset();
0076 
0077     bool needsModeset() const;
0078     void applyPendingChanges();
0079     void revertPendingChanges();
0080 
0081     bool updateCursor();
0082 
0083     DrmConnector *connector() const;
0084     DrmGpu *gpu() const;
0085 
0086     enum class PageflipType {
0087         Normal,
0088         CursorOnly,
0089         Modeset,
0090     };
0091     void pageFlipped(std::chrono::nanoseconds timestamp, PageflipType type, PresentationMode mode);
0092     bool pageflipsPending() const;
0093     bool modesetPresentPending() const;
0094     void resetModesetPresentPending();
0095 
0096     QMap<uint32_t, QList<uint64_t>> formats() const;
0097     QMap<uint32_t, QList<uint64_t>> cursorFormats() const;
0098     bool hasCTM() const;
0099     bool hasGammaRamp() const;
0100     bool pruneModifier();
0101 
0102     void setOutput(DrmOutput *output);
0103     DrmOutput *output() const;
0104 
0105     void setLayers(const std::shared_ptr<DrmPipelineLayer> &primaryLayer, const std::shared_ptr<DrmPipelineLayer> &cursorLayer);
0106     DrmPipelineLayer *primaryLayer() const;
0107     DrmPipelineLayer *cursorLayer() const;
0108     std::chrono::nanoseconds presentationDeadline() const;
0109 
0110     DrmCrtc *crtc() const;
0111     std::shared_ptr<DrmConnectorMode> mode() const;
0112     bool active() const;
0113     bool activePending() const;
0114     bool enabled() const;
0115     DrmPlane::Transformations renderOrientation() const;
0116     PresentationMode presentationMode() const;
0117     uint32_t overscan() const;
0118     Output::RgbRange rgbRange() const;
0119     DrmConnector::DrmContentType contentType() const;
0120     const ColorDescription &colorDescription() const;
0121     const std::shared_ptr<IccProfile> &iccProfile() const;
0122 
0123     void setCrtc(DrmCrtc *crtc);
0124     void setMode(const std::shared_ptr<DrmConnectorMode> &mode);
0125     void setActive(bool active);
0126     void setEnable(bool enable);
0127     void setRenderOrientation(DrmPlane::Transformations orientation);
0128     void setPresentationMode(PresentationMode mode);
0129     void setOverscan(uint32_t overscan);
0130     void setRgbRange(Output::RgbRange range);
0131     void setGammaRamp(const std::shared_ptr<ColorTransformation> &transformation);
0132     void setCTM(const QMatrix3x3 &ctm);
0133     void setContentType(DrmConnector::DrmContentType type);
0134     void setColorDescription(const ColorDescription &description);
0135     void setIccProfile(const std::shared_ptr<IccProfile> &profile);
0136 
0137     enum class CommitMode {
0138         Test,
0139         TestAllowModeset,
0140         CommitModeset
0141     };
0142     Q_ENUM(CommitMode)
0143     static Error commitPipelines(const QList<DrmPipeline *> &pipelines, CommitMode mode, const QList<DrmObject *> &unusedObjects = {});
0144 
0145 private:
0146     bool isBufferForDirectScanout() const;
0147     uint32_t calculateUnderscan();
0148     static Error errnoToError();
0149     std::shared_ptr<DrmBlob> createHdrMetadata(NamedTransferFunction transferFunction) const;
0150 
0151     // legacy only
0152     Error presentLegacy();
0153     Error legacyModeset();
0154     Error applyPendingChangesLegacy();
0155     bool setCursorLegacy();
0156     static Error commitPipelinesLegacy(const QList<DrmPipeline *> &pipelines, CommitMode mode);
0157 
0158     // atomic modesetting only
0159     Error prepareAtomicCommit(DrmAtomicCommit *commit, CommitMode mode);
0160     bool prepareAtomicModeset(DrmAtomicCommit *commit);
0161     Error prepareAtomicPresentation(DrmAtomicCommit *commit);
0162     void prepareAtomicCursor(DrmAtomicCommit *commit);
0163     void prepareAtomicDisable(DrmAtomicCommit *commit);
0164     static Error commitPipelinesAtomic(const QList<DrmPipeline *> &pipelines, CommitMode mode, const QList<DrmObject *> &unusedObjects);
0165 
0166     DrmOutput *m_output = nullptr;
0167     DrmConnector *m_connector = nullptr;
0168 
0169     bool m_modesetPresentPending = false;
0170 
0171     struct State
0172     {
0173         DrmCrtc *crtc = nullptr;
0174         QMap<uint32_t, QList<uint64_t>> formats;
0175         bool active = true; // whether or not the pipeline should be currently used
0176         bool enabled = true; // whether or not the pipeline needs a crtc
0177         bool needsModeset = false;
0178         bool needsModesetProperties = false;
0179         std::shared_ptr<DrmConnectorMode> mode;
0180         uint32_t overscan = 0;
0181         Output::RgbRange rgbRange = Output::RgbRange::Automatic;
0182         PresentationMode presentationMode = PresentationMode::VSync;
0183         std::shared_ptr<ColorTransformation> colorTransformation;
0184         std::shared_ptr<DrmGammaRamp> gamma;
0185         std::shared_ptr<DrmBlob> ctm;
0186         DrmConnector::DrmContentType contentType = DrmConnector::DrmContentType::Graphics;
0187 
0188         std::shared_ptr<IccProfile> iccProfile;
0189         ColorDescription colorDescription = ColorDescription::sRGB;
0190 
0191         // the transformation that buffers submitted to the pipeline should have
0192         DrmPlane::Transformations renderOrientation = DrmPlane::Transformation::Rotate0;
0193     };
0194     // the state that is to be tested next
0195     State m_pending;
0196     // the state that will be applied at the next real atomic commit
0197     State m_next;
0198 
0199     std::unique_ptr<DrmCommitThread> m_commitThread;
0200     std::shared_ptr<DrmPipelineLayer> m_primaryLayer;
0201     std::shared_ptr<DrmPipelineLayer> m_cursorLayer;
0202 };
0203 
0204 }