1 /*
2     KWin - the KDE window manager
3     This file is part of the KDE project.
4 
5     SPDX-FileCopyrightText: 2016 Roman Gilg <subdiff@gmail.com>
6 
7     SPDX-License-Identifier: GPL-2.0-or-later
8 */
9 #pragma once
10 
11 #include <QVector>
12 #include <QByteArray>
13 #include <QMap>
14 
15 // drm
16 #include <xf86drmMode.h>
17 
18 #include "drm_pointer.h"
19 
20 namespace KWin
21 {
22 
23 class DrmBackend;
24 class DrmGpu;
25 class DrmOutput;
26 
27 class DrmObject
28 {
29 public:
30     virtual ~DrmObject();
31 
32     /**
33      * Must be called to query necessary data directly after creation.
34      * @return true when initializing was successful
35      */
36     virtual bool init() = 0;
37 
id()38     uint32_t id() const {
39         return m_id;
40     }
41 
gpu()42     DrmGpu *gpu() const {
43         return m_gpu;
44     }
45 
46     /**
47      * Populate an atomic request with data of this object.
48      * @param req the atomic request
49      * @return true when the request was successfully populated
50      */
51     bool atomicPopulate(drmModeAtomicReq *req) const;
52 
53     template <typename T>
setPending(T prop,uint64_t new_value)54     bool setPending(T prop, uint64_t new_value)
55     {
56         if (auto &property = m_props.at(static_cast<uint32_t>(prop))) {
57             property->setPending(new_value);
58             return true;
59         }
60         return false;
61     }
62 
63     template <typename T>
setPendingBlob(T prop,void * data,size_t length)64     bool setPendingBlob(T prop, void *data, size_t length)
65     {
66         if (auto &property = m_props.at(static_cast<uint32_t>(prop))) {
67             return property->setPendingBlob(data, length);
68         }
69         return false;
70     }
71 
72     template <typename T>
propHasEnum(T prop,uint64_t value)73     bool propHasEnum(T prop, uint64_t value) const
74     {
75         const auto &property = m_props.at(static_cast<uint32_t>(prop));
76         return property ? property->hasEnum(value) : false;
77     }
78 
79     class Property
80     {
81     public:
82         Property(DrmGpu *gpu, drmModePropertyRes *prop, uint64_t val, const QVector<QByteArray> &enumNames);
83         virtual ~Property();
84 
85         void initEnumMap(drmModePropertyRes *prop);
86 
enumNames()87         QVector<QByteArray> enumNames() const {
88             return m_enumNames;
89         }
hasEnum(uint64_t value)90         bool hasEnum(uint64_t value) const {
91             return m_enumMap.contains(value);
92         }
hasAllEnums()93         bool hasAllEnums() const {
94             return m_enumMap.count() == m_enumNames.count();
95         }
96         template <typename T>
enumForValue(uint64_t value)97         T enumForValue(uint64_t value) const {
98             return static_cast<T>(m_enumMap[value]);
99         }
100         template <typename T>
setEnum(T index)101         bool setEnum(T index) {
102             if (hasEnum(static_cast<uint64_t>(index))) {
103                 setPending(m_enumMap[static_cast<uint32_t>(index)]);
104                 return true;
105             }
106             return false;
107         }
108 
propId()109         uint32_t propId() const {
110             return m_propId;
111         }
name()112         const QByteArray &name() const {
113             return m_propName;
114         }
isImmutable()115         bool isImmutable() const {
116             return m_immutable;
117         }
isLegacy()118         bool isLegacy() const {
119             return m_legacy;
120         }
121         /**
122          * Makes this property be ignored by DrmObject::atomicPopulate
123          */
setLegacy()124         void setLegacy() {
125             m_legacy = true;
126         }
127 
128         void setPending(uint64_t value);
129         uint64_t pending() const;
130         bool setPendingBlob(void *blob, size_t length);
131 
132         void setCurrent(uint64_t value);
133         uint64_t current() const;
134         void setCurrentBlob(drmModePropertyBlobRes *blob);
135 
136         void commit();
137         void commitPending();
138         void rollbackPending();
139         bool needsCommit() const;
140 
141     private:
142         uint32_t m_propId = 0;
143         QByteArray m_propName;
144 
145         // the value that will be m_next after the property has been committed
146         // has not necessarily been tested to work
147         uint64_t m_pending = 0;
148         drmModePropertyBlobRes *m_pendingBlob = nullptr;
149         // the value that will be m_current after the next atomic commit
150         // and has been tested to work
151         uint64_t m_next = 0;
152         drmModePropertyBlobRes *m_nextBlob = nullptr;
153         // the value currently set for or by the kernel
154         uint64_t m_current = 0;
155         drmModePropertyBlobRes *m_currentBlob = nullptr;
156 
157         QMap<uint32_t, uint64_t> m_enumMap;
158         QVector<QByteArray> m_enumNames;
159         const bool m_immutable;
160         bool m_legacy = false;
161         const DrmGpu *m_gpu;
162     };
163 
164     template <typename T>
getProp(T propIndex)165     Property *getProp(T propIndex) const {
166         return m_props[static_cast<uint32_t>(propIndex)];
167     }
168 
169     QVector<Property*> properties();
170     void commit();
171     void commitPending();
172     void rollbackPending();
173 
174     bool needsCommit() const;
175     virtual bool needsModeset() const = 0;
176 
177     virtual bool updateProperties();
178 
179 protected:
180     enum class Requirement {
181         Required,
182         Optional
183     };
184     struct PropertyDefinition
185     {
186         PropertyDefinition(const QByteArray &name, Requirement requirement, const QVector<QByteArray> &&enumNames = {})
namePropertyDefinition187             : name(name)
188             , requirement(requirement)
189             , enumNames(enumNames)
190         {
191         }
192         QByteArray name;
193         Requirement requirement;
194         QVector<QByteArray> enumNames;
195     };
196 
197     DrmObject(DrmGpu *gpu, uint32_t objectId, const QVector<PropertyDefinition> &&vector, uint32_t objectType);
198 
199     bool initProps();
200 
201     template <typename T>
deleteProp(T prop)202     void deleteProp(T prop)
203     {
204         delete m_props[static_cast<uint32_t>(prop)];
205         m_props[static_cast<uint32_t>(prop)] = nullptr;
206     }
207 
208     QVector<Property *> m_props;
209 
210 private:
211     DrmGpu *m_gpu;
212     const uint32_t m_id;
213     const uint32_t m_objectType;
214     const QVector<PropertyDefinition> m_propertyDefinitions;
215 };
216 
217 }
218 
219 QDebug operator<<(QDebug stream, const KWin::DrmObject*);
220