Beatmup
drm.hpp
Go to the documentation of this file.
1 /*
2  Beatmup image and signal processing library
3  Copyright (C) 2021, lnstadrum
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #pragma once
20 #include "../exception.h"
21 
22 #include <cstdint>
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <xf86drm.h>
26 #include <xf86drmMode.h>
27 #include <gbm.h>
28 
29 namespace Beatmup {
30  /**
31  * Low-level DRM/GBM primitives.
32  * This file is not expected to be included in the application code, and only used by the graphic pipeline to get access to the GPU.
33  * Following RAII paradigm and enabling move construction to free acquired resources in case of error and move them to persistent storages
34  * when everything is set up.
35  */
36  namespace DRM {
37  class DRMError : public Beatmup::Exception {
38  public:
39  DRMError(const std::string& info) : Exception(info.c_str()) {}
40  };
41 
42  class Device {
43  Device(const Device&) = delete;
44  private:
45  int device;
46  public:
47  Device(): device(0) {}
48 
49  Device(const char* path) {
50  device = open(path, O_RDWR | O_CLOEXEC);
51  if (device == 0)
52  throw DRMError(std::string("Cannot open DRM device") + path);
53  }
54 
55  ~Device() {
56  if (device != 0)
57  close(device);
58  }
59 
60  Device& operator=(Device&& other) {
61  device = other.device;
62  other.device = 0;
63  return *this;
64  }
65 
66  int getHandle() { return device; }
67 
68  operator bool() const {
69  return device != 0;
70  }
71  };
72 
73 
74  class ModeResources {
75  ModeResources(const ModeResources&) = delete;
76  private:
77  drmModeRes* resources;
78  public:
79  ModeResources(): resources(nullptr) {}
80 
81  ModeResources(Device& device) {
82  resources = drmModeGetResources(device.getHandle());
83  if (!resources)
84  throw DRMError("Cannot get DRM resources");
85  }
86 
88  if (resources)
89  drmModeFreeResources(resources);
90  }
91 
92  drmModeRes* getPointer() { return resources; }
93  };
94 
95 
96  class ModeConnector {
97  ModeConnector(const ModeConnector&) = delete;
98  private:
99  drmModeConnector* connector;
100  public:
101  ModeConnector(): connector(nullptr) {}
102 
103  ModeConnector(Device& device, ModeResources& resources): connector(nullptr) {
104  auto* resPtr = resources.getPointer();
105  for (int i = 0; i < resPtr->count_connectors; ++i) {
106  connector = drmModeGetConnector(device.getHandle(), resPtr->connectors[i]);
107  if (connector->connection == DRM_MODE_CONNECTED)
108  break;
109  }
110  if (!connector)
111  throw DRMError("Cannot get DRM connector");
112  }
113 
115  if (connector)
116  drmModeFreeConnector(connector);
117  }
118 
120  connector = other.connector;
121  other.connector = nullptr;
122  return *this;
123  }
124 
125  drmModeConnector* getPointer() { return connector; }
126 
127  const drmModeModeInfo& getMode(int index) const { return connector->modes[index]; }
128  };
129 
130 
131  class ModeEncoder {
132  ModeEncoder(const ModeEncoder&) = delete;
133  private:
134  drmModeEncoder* encoder;
135  public:
136  ModeEncoder(): encoder(nullptr) {}
137 
138  ModeEncoder(Device& device, ModeConnector& connector): encoder(nullptr) {
139  auto id = connector.getPointer()->encoder_id;
140  if (!id)
141  throw DRMError("Cannot get DRM encoder");
142  encoder = drmModeGetEncoder(device.getHandle(), id);
143  }
144 
146  if (encoder)
147  drmModeFreeEncoder(encoder);
148  }
149 
151  encoder = other.encoder;
152  other.encoder = nullptr;
153  return *this;
154  }
155 
156 
157  drmModeEncoder* getPointer() { return encoder; }
158  };
159 
160 
161  class ModeCrtc {
162  ModeCrtc(const ModeCrtc&) = delete;
163  private:
164  int device;
165  uint32_t connector;
166  drmModeCrtc* crtc;
167  public:
168  ModeCrtc(): crtc(nullptr) {}
169 
171  device(device.getHandle()),
172  connector(connector.getPointer()->connector_id),
173  crtc(drmModeGetCrtc(this->device, encoder.getPointer()->crtc_id))
174  {
175  if (!crtc)
176  throw DRMError("Cannot get DRM crtc");
177  }
178 
180  if (crtc) {
181  drmModeSetCrtc(device, crtc->crtc_id, crtc->buffer_id, crtc->x, crtc->y, &connector, 1, &crtc->mode);
182  drmModeFreeCrtc(crtc);
183  }
184  }
185 
187  device = other.device;
188  connector = other.connector;
189  crtc = other.crtc;
190  other.crtc = nullptr;
191  return *this;
192  }
193  };
194 
195 
196  class GBMDevice {
197  GBMDevice(const GBMDevice&) = delete;
198  private:
199  struct gbm_device *device;
200  public:
201  GBMDevice(): device(nullptr) {}
202 
203  GBMDevice(Device& driDevice, ModeConnector& connector): device(nullptr) {
204  device = gbm_create_device(driDevice.getHandle());
205  if (!device)
206  throw DRMError("Cannot get GBM device");
207  }
208 
210  if (device)
211  gbm_device_destroy(device);
212  }
213 
215  device = other.device;
216  other.device = nullptr;
217  return *this;
218  }
219 
220  struct gbm_device* getPointer() {
221  return device;
222  }
223  };
224 
225 
226  class GBMSurface {
227  GBMSurface(const GBMSurface&) = delete;
228  private:
229  struct gbm_surface *surface;
230  public:
231  static const int FORMAT = GBM_FORMAT_XRGB8888;
232 
233  GBMSurface(): surface(nullptr) {}
234 
235  GBMSurface(GBMDevice& gbmDevice, const ModeConnector& connector): surface(nullptr) {
236  const auto& mode = connector.getMode(0);
237 
238  surface = gbm_surface_create(
239  gbmDevice.getPointer(),
240  mode.hdisplay,
241  mode.vdisplay,
242  FORMAT,
243  GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING
244  );
245  if (!surface)
246  throw DRMError("Cannot create GBM surface");
247  }
248 
250  if (surface)
251  gbm_surface_destroy(surface);
252  }
253 
255  surface = other.surface;
256  other.surface = nullptr;
257  return *this;
258  }
259 
260  struct gbm_surface* getPointer() {
261  return surface;
262  }
263  };
264 
265  }
266 }
DRMError(const std::string &info)
Definition: drm.hpp:39
Device(const Device &)=delete
Device(const char *path)
Definition: drm.hpp:49
Device & operator=(Device &&other)
Definition: drm.hpp:60
struct gbm_device * getPointer()
Definition: drm.hpp:220
struct gbm_device * device
Definition: drm.hpp:199
GBMDevice(const GBMDevice &)=delete
GBMDevice & operator=(GBMDevice &&other)
Definition: drm.hpp:214
GBMDevice(Device &driDevice, ModeConnector &connector)
Definition: drm.hpp:203
GBMSurface(const GBMSurface &)=delete
static const int FORMAT
Definition: drm.hpp:231
GBMSurface(GBMDevice &gbmDevice, const ModeConnector &connector)
Definition: drm.hpp:235
GBMSurface & operator=(GBMSurface &&other)
Definition: drm.hpp:254
struct gbm_surface * surface
Definition: drm.hpp:229
struct gbm_surface * getPointer()
Definition: drm.hpp:260
const drmModeModeInfo & getMode(int index) const
Definition: drm.hpp:127
ModeConnector(const ModeConnector &)=delete
ModeConnector(Device &device, ModeResources &resources)
Definition: drm.hpp:103
drmModeConnector * getPointer()
Definition: drm.hpp:125
drmModeConnector * connector
Definition: drm.hpp:99
ModeConnector & operator=(ModeConnector &&other)
Definition: drm.hpp:119
drmModeCrtc * crtc
Definition: drm.hpp:166
ModeCrtc & operator=(ModeCrtc &&other)
Definition: drm.hpp:186
uint32_t connector
Definition: drm.hpp:165
ModeCrtc(Device &device, ModeEncoder &encoder, ModeConnector &connector)
Definition: drm.hpp:170
ModeCrtc(const ModeCrtc &)=delete
ModeEncoder(const ModeEncoder &)=delete
ModeEncoder & operator=(ModeEncoder &&other)
Definition: drm.hpp:150
ModeEncoder(Device &device, ModeConnector &connector)
Definition: drm.hpp:138
drmModeEncoder * encoder
Definition: drm.hpp:134
drmModeEncoder * getPointer()
Definition: drm.hpp:157
drmModeRes * resources
Definition: drm.hpp:77
ModeResources(Device &device)
Definition: drm.hpp:81
ModeResources(const ModeResources &)=delete
drmModeRes * getPointer()
Definition: drm.hpp:92
Base class for all exceptions.
Definition: exception.h:37
jlong jint index
collection close()
JNIEnv jlong jint mode