vdr-plugin-softhddevice-drm-gles 1.6.4-d0291bb
drmdevice.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: AGPL-3.0-or-later
2
16#include <cerrno>
17#include <cstdint>
18#include <cstdio>
19#include <cstring>
20#include <cinttypes>
21#include <vector>
22
23#include <fcntl.h>
24#include <unistd.h>
25
26#ifdef USE_GLES
27#include <assert.h>
28#include <EGL/egl.h>
29#include <EGL/eglext.h>
30#endif
31
32#include <drm_fourcc.h>
33#include <xf86drm.h>
34#include <xf86drmMode.h>
35
36#include "drmdevice.h"
37#include "drmplane.h"
38#include "logger.h"
39#include "videorender.h"
40
47cDrmDevice::cDrmDevice(cVideoRender *render, const char* resolution, const char* device)
48 : m_pRender(render),
49 m_userDrmDevice(device)
50{
51 if (resolution)
53}
54
56{
57 LOGDEBUG2(L_DRM, "drmdevice: %s", __FUNCTION__);
58}
59
62{
64 if (*resources == NULL) {
65 LOGERROR("drmdevice: %s: cannot retrieve DRM resources (%d): %m", __FUNCTION__, errno);
66 return -1;
67 }
68 return 0;
69}
70
77static int TestCaps(int fd)
78{
80
81 if (drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &test) < 0 || test == 0)
82 return 1;
83
85 return 1;
86
88 return 1;
89
90 if (drmGetCap(fd, DRM_CAP_PRIME, &test) < 0)
91 return 1;
92
94 return 1;
95
97 return 1;
98
99 return 0;
100}
101
112static int OpenDrmDevice(const char* device, drmModeRes **resources)
113{
114 int fd = -1;
115
116 if ((fd = open(device, O_RDWR)) < 0)
117 return -1;
118
120 close(fd);
121 return -1;
122 }
123
124 return fd;
125}
126
135{
136 int MAX_DRM_DEVICES = 64;
137
139 int num_devices, fd = -1;
140
142 if (num_devices < 0) {
143 LOGERROR("drmdevice: %s: drmGetDevices2 failed: %s", __FUNCTION__, strerror(-num_devices));
144 return fd;
145 }
146
147 for (int i = 0; i < num_devices && fd < 0; i++) {
148 drmDevicePtr device = devices[i];
149 int ret;
150
151 if (!(device->available_nodes & (1 << DRM_NODE_PRIMARY)))
152 continue;
153 fd = open(device->nodes[DRM_NODE_PRIMARY], O_RDWR);
154 if (fd < 0)
155 continue;
156
157 if (TestCaps(fd)) {
158 close(fd);
159 fd = -1;
160 continue;
161 }
162
164 if (!ret)
165 break;
166 close(fd);
167 fd = -1;
168 }
170
171 if (fd < 0)
172 LOGERROR("drmdevice: %s: no drm device found!", __FUNCTION__);
173
174 return fd;
175}
176
183{
185 int i;
186
187 // search for a connected connector
188 for (i = 0; i < resources->count_connectors; i++) {
189 connector = drmModeGetConnector(fd, resources->connectors[i]);
190 if (connector && connector->connection == DRM_MODE_CONNECTED)
191 return connector;
193 connector = NULL;
194 }
195
196 // search for a not connected connector, but with available modes
197 // this is a workaround for RPI: in case we don't have a monitor connected
198 // we can load an edid file at boot time, where the available modes are listed.
199 // To bring softhddevice up, we also have to go through the not connected connectors
200 for (i = 0; i < resources->count_connectors; i++) {
201 connector = drmModeGetConnector(fd, resources->connectors[i]);
202 if (connector && connector->count_modes > 0)
203 return connector;
205 connector = NULL;
206 }
207
208 // we couldn't find a connector
209 return connector;
210}
211
212
220{
221 drmModeRes *resources = nullptr;
223 drmModeEncoder *encoder = nullptr;
224 drmModeModeInfo *drmmode = nullptr;
227 int i;
228 uint32_t j, k;
229
230 // first try to open the user given drm device
231 if (m_userDrmDevice) {
232 LOGDEBUG2(L_DRM, "drmdevice: %s: Try open user requested device %s", __FUNCTION__, m_userDrmDevice);
234 }
235
236 // if manually set device failed, try to find a drm device
237 if (m_fdDrm < 0) {
238 if (m_userDrmDevice)
239 LOGWARNING("drmdevice: %s: Could not open user requested device %s, try other devices!", __FUNCTION__, m_userDrmDevice);
241 }
242
243 if (m_fdDrm < 0) {
244 LOGERROR("drmdevice: %s: Could not open device!", __FUNCTION__);
245 return -1;
246 }
247
248 LOGDEBUG2(L_DRM, "drmdevice: %s: fd: %d DRM have %i connectors, %i crtcs, %i encoders", __FUNCTION__,
249 m_fdDrm, resources->count_connectors, resources->count_crtcs,
250 resources->count_encoders);
251
252 // find a connector
254 if (!connector) {
255 LOGERROR("drmdevice: %s: cannot retrieve DRM connector (%d): %m", __FUNCTION__, errno);
256 return -errno;
257 }
258 m_connectorId = connector->connector_id;
259
260 // find a user requested mode
262 for (i = 0; i < connector->count_modes; i++) {
267 LOGDEBUG2(L_DRM, "drmdevice: %s: Use user requested mode: %dx%d@%d", __FUNCTION__, drmmode->hdisplay, drmmode->vdisplay, drmmode->vrefresh);
268 break;
269 }
270 }
271 if (!drmmode)
272 LOGWARNING("drmdevice: %s: User requested mode not found, try default modes", __FUNCTION__);
273 }
274
275 uint32_t preferred_hz[3] = {50, 60, 0};
276
277 // find the highest resolution mode with 50, 60 or any refresh rate
278 if (!drmmode) {
279 j = 0;
280 int width;
281 while (!drmmode && preferred_hz[j]) {
282 for (i = 0, width = 0; i < connector->count_modes; i++) {
284 if (preferred_hz[j] && current_mode->vrefresh != preferred_hz[j])
285 continue;
286
287 int current_width = current_mode->hdisplay;
288 if (current_width > width) {
290 width = current_width;
291 }
292 }
293 j++;
294 }
295
296 if (drmmode)
297 LOGDEBUG2(L_DRM, "drmdevice: %s: Use mode with the biggest width: %dx%d@%d", __FUNCTION__,
298 drmmode->hdisplay, drmmode->vdisplay, drmmode->vrefresh);
299 }
300
301 if (!drmmode) {
302 LOGERROR("drmdevice: %s: No monitor mode found! Probably no monitor connected, giving up!", __FUNCTION__);
303 return -1;
304 }
305
307
308 // find encoder
309 for (i = 0; i < resources->count_encoders; i++) {
311 if (encoder->encoder_id == connector->encoder_id)
312 break;
314 encoder = NULL;
315 }
316
317 if (encoder) {
318 m_crtcId = encoder->crtc_id;
319 LOGDEBUG2(L_DRM, "drmdevice: %s: have encoder, m_crtcId %d", __FUNCTION__, m_crtcId);
320 } else {
322 if (crtc_id == -1) {
323 LOGERROR("drmdevice: %s: No crtc found!", __FUNCTION__);
324 return -errno;
325 }
326
328 LOGDEBUG2(L_DRM, "drmdevice: %s: have no encoder, m_crtcId %d", __FUNCTION__, m_crtcId);
329 }
330
331 for (i = 0; i < resources->count_crtcs; i++) {
332 if (resources->crtcs[i] == m_crtcId) {
333 m_crtcIndex = i;
334 break;
335 }
336 }
337
339 if (m_hdrMetadata != 0)
340 LOGDEBUG2(L_DRM, "drmdevice: %s: HDR output metadata ID %d in connector %d", __FUNCTION__, m_hdrMetadata, m_connectorId);
341
342 // Calculate the refresh rate. Don't use m_drmModeInfo.vrefresh, because we need the precise value.
343 double refreshRateHz = (double)m_drmModeInfo.clock * 1000.0 / ((double)m_drmModeInfo.htotal * (double)m_drmModeInfo.vtotal);
344
346
347 LOGINFO("DRM Setup: Using Monitor Mode %dx%d@%.2fHz, m_crtcId %d crtc_idx %d",
349
351
352
353 // find planes
355 LOGERROR("drmdevice: %s: cannot retrieve PlaneResources (%d): %m", __FUNCTION__, errno);
356 return -1;
357 }
358
359 // test and list the local planes
360 cDrmPlane best_primary_video_plane; // NV12 capable primary plane with the lowest plane_id
361 cDrmPlane best_overlay_video_plane; // NV12 capable overlay plane with the lowest plane_id
362 cDrmPlane best_primary_osd_plane; // AR24 capable primary plane with the highest plane_id
363 cDrmPlane best_overlay_osd_plane; // AR24 capable overlay plane with the highest plane_id
364
365 // collect candidates for pip (NV12 overlay plane). The best one is chosen after we decided which
366 // planes are used for video and osd
367 std::vector<cDrmPlane> overlayNV12Candidates;
368
369 for (j = 0; j < planeRes->count_planes; j++) {
371
372 if (plane == NULL) {
373 LOGERROR("drmdevice: %s: cannot query DRM-KMS plane %d", __FUNCTION__, j);
374 continue;
375 }
376
377 uint64_t type = 0;
378 uint64_t zpos = 0;
379 char pixelformats[256];
380
381 if (plane->possible_crtcs & (1 << m_crtcIndex)) {
382 if (GetPropertyValue(planeRes->planes[j], DRM_MODE_OBJECT_PLANE, "type", &type)) {
383 LOGDEBUG2(L_DRM, "drmdevice: %s: Failed to get property 'type'", __FUNCTION__);
384 }
385 if (GetPropertyValue(planeRes->planes[j], DRM_MODE_OBJECT_PLANE, "zpos", &zpos)) {
386 LOGDEBUG2(L_DRM, "drmdevice: %s: Failed to get property 'zpos'", __FUNCTION__);
387 } else {
388 m_useZpos = true;
389 }
390
391 LOGDEBUG2(L_DRM, "drmdevice: %s: %s: id %i possible_crtcs %i", __FUNCTION__,
392 (type == DRM_PLANE_TYPE_PRIMARY) ? "PRIMARY " :
393 (type == DRM_PLANE_TYPE_OVERLAY) ? "OVERLAY " :
394 (type == DRM_PLANE_TYPE_CURSOR) ? "CURSOR " : "UNKNOWN",
395 plane->plane_id, plane->possible_crtcs);
396 strcpy(pixelformats, " ");
397
398 // test pixel format and plane caps
399 for (k = 0; k < plane->count_formats; k++) {
400 if (encoder->possible_crtcs & plane->possible_crtcs) {
401 char tmp[10];
402 switch (plane->formats[k]) {
403 case DRM_FORMAT_NV12:
404 snprintf(tmp, sizeof(tmp), " %4.4s", (char *)&plane->formats[k]);
406 if (type == DRM_PLANE_TYPE_PRIMARY && !best_primary_video_plane.GetId()) {
407 best_primary_video_plane.SetId(plane->plane_id);
408 best_primary_video_plane.SetType(type);
410 strcat(pixelformats, "! ");
411 }
412 if (type == DRM_PLANE_TYPE_OVERLAY && !best_overlay_video_plane.GetId()) {
413 best_overlay_video_plane.SetId(plane->plane_id);
414 best_overlay_video_plane.SetType(type);
416 strcat(pixelformats, "! ");
417 }
418 // store overlay NV12 plane as a candidate for pip
419 if (type == DRM_PLANE_TYPE_OVERLAY) {
421 cand.SetId(plane->plane_id);
422 cand.SetType(type);
423 cand.SetZpos(zpos);
424 overlayNV12Candidates.push_back(cand);
425 }
426 break;
428 snprintf(tmp, sizeof(tmp), " %4.4s", (char *)&plane->formats[k]);
430 if (type == DRM_PLANE_TYPE_PRIMARY) {
431 best_primary_osd_plane.SetId(plane->plane_id);
432 best_primary_osd_plane.SetType(type);
434 strcat(pixelformats, "! ");
435 }
436 if (type == DRM_PLANE_TYPE_OVERLAY) {
437 best_overlay_osd_plane.SetId(plane->plane_id);
438 best_overlay_osd_plane.SetType(type);
440 strcat(pixelformats, "! ");
441 }
442 break;
443 default:
444 break;
445 }
446 }
447 }
448 LOGDEBUG2(L_DRM, "drmdevice: %s", __FUNCTION__, pixelformats);
449 }
451 }
452
453 // See which planes we should use for video and osd
454 if (best_primary_video_plane.GetId() && best_overlay_osd_plane.GetId()) {
463 } else if (best_overlay_video_plane.GetId() && best_primary_osd_plane.GetId()) {
472 m_useZpos = true;
473 } else {
474 LOGERROR("drmdevice: %s: No suitable planes found!", __FUNCTION__);
475 return -1;
476 }
477
478 // now pick the best pip plane from the NV12 overlay candidates we collected above
481 uint32_t pid = cand.GetId();
482 if (pid == m_videoPlane.GetId() || pid == m_osdPlane.GetId())
483 continue;
484 if (!best_overlay_pip_plane.GetId() || pid > best_overlay_pip_plane.GetId()) {
486 }
487 }
488
489 if (best_overlay_pip_plane.GetId()) {
494 } else {
495 LOGWARNING("drmdevice: %s: No suitable plane for Picture-in-Picture found. PIP will be disabled.", __FUNCTION__);
496 }
497
498 // debug output
499 if (best_primary_video_plane.GetId()) {
500 LOGDEBUG2(L_DRM, "drmdevice: %s: best_primary_video_plane: plane_id %d, type %s, zpos %" PRIu64 "", __FUNCTION__,
501 best_primary_video_plane.GetId(), best_primary_video_plane.GetType() == DRM_PLANE_TYPE_PRIMARY ? "PRIMARY" : "OVERLAY", best_primary_video_plane.GetZpos());
502 }
503 if (best_overlay_video_plane.GetId()) {
504 LOGDEBUG2(L_DRM, "drmdevice: %s: best_overlay_video_plane: plane_id %d, type %s, zpos %" PRIu64 "", __FUNCTION__,
505 best_overlay_video_plane.GetId(), best_overlay_video_plane.GetType() == DRM_PLANE_TYPE_PRIMARY ? "PRIMARY" : "OVERLAY", best_overlay_video_plane.GetZpos());
506 }
507 if (best_primary_osd_plane.GetId()) {
508 LOGDEBUG2(L_DRM, "drmdevice: %s: best_primary_osd_plane: plane_id %d, type %s, zpos %" PRIu64 "", __FUNCTION__,
509 best_primary_osd_plane.GetId(), best_primary_osd_plane.GetType() == DRM_PLANE_TYPE_PRIMARY ? "PRIMARY" : "OVERLAY", best_primary_osd_plane.GetZpos());
510 }
511 if (best_overlay_osd_plane.GetId()) {
512 LOGDEBUG2(L_DRM, "drmdevice: %s: best_overlay_osd_plane: plane_id %d, type %s, zpos %" PRIu64 "", __FUNCTION__,
513 best_overlay_osd_plane.GetId(), best_overlay_osd_plane.GetType() == DRM_PLANE_TYPE_PRIMARY ? "PRIMARY" : "OVERLAY", best_overlay_osd_plane.GetZpos());
514 }
515 if (best_overlay_pip_plane.GetId()) {
516 LOGDEBUG2(L_DRM, "drmdevice: %s: best_overlay_pip_plane: plane_id %d, type %s, zpos %" PRIu64 "", __FUNCTION__,
517 best_overlay_pip_plane.GetId(), best_overlay_pip_plane.GetType() == DRM_PLANE_TYPE_PRIMARY ? "PRIMARY" : "OVERLAY", best_overlay_pip_plane.GetZpos());
518 }
519
520 // fill the plane's properties to speed up SetPropertyRequest later
523
524 if (m_pipPlane.GetId())
526
527 // Check, if we can set z-order (meson and rpi have fixed z-order, which cannot be changed)
529 m_useZpos = false;
530 }
532 m_useZpos = false;
533 }
535 m_useZpos = false;
536 }
537
538 // m_useZpos was set, if video is on OVERLAY, and osd is on PRIMARY
539 // Check if the OVERLAY plane really got a higher zpos than the PRIMARY plane
540 // If not, change their zpos values or hardcode them to
541 // 1 OVERLAY (Video)
542 // 0 PRIMARY (Osd)
544 char str_zpos[256];
545 strcpy(str_zpos, "drmdevice: Init: zpos values are wrong, so ");
547 // is this possible?
548 strcat(str_zpos, "hardcode them to 0 and 1, because they are equal");
549 m_zposPrimary = 0;
550 m_zposOverlay = 1;
551 } else {
552 strcat(str_zpos, "switch them");
556 }
557 LOGDEBUG2(L_DRM, "%s", str_zpos);
558 }
559
560 if (drmSetMaster(m_fdDrm) < 0) {
561 LOGDEBUG2(L_DRM, "drmdevice: Failed to set drm master, try authorize instead: {}", strerror(errno));
562
564 if (drmGetMagic(m_fdDrm, &magic) < 0)
565 LOGFATAL("drmdevice: Failed to get drm magic: {}", strerror(errno));
566
567 if (drmAuthMagic(m_fdDrm, magic) < 0)
568 LOGFATAL("drmdevice: Failed to authorize drm magic: {}", strerror(errno));
569 }
570
574
575 if (m_pipPlane.GetId()) {
576 LOGINFO("DRM setup - CRTC: %i video_plane: %i (%s %" PRIu64 ") osd_plane: %i (%s %" PRIu64 ") pip_plane: %i (%s %" PRIu64 ") m_useZpos: %d",
577 m_crtcId,
579 m_videoPlane.GetType() == DRM_PLANE_TYPE_PRIMARY ? "PRIMARY" : "OVERLAY",
582 m_osdPlane.GetType() == DRM_PLANE_TYPE_PRIMARY ? "PRIMARY" : "OVERLAY",
585 m_pipPlane.GetType() == DRM_PLANE_TYPE_PRIMARY ? "PRIMARY" : "OVERLAY",
587 m_useZpos);
588 } else {
589 LOGINFO("DRM setup - CRTC: %i video_plane: %i (%s %" PRIu64 ") osd_plane: %i (%s %" PRIu64 ") m_useZpos: %d (pip disbled)",
590 m_crtcId,
592 m_videoPlane.GetType() == DRM_PLANE_TYPE_PRIMARY ? "PRIMARY" : "OVERLAY",
595 m_osdPlane.GetType() == DRM_PLANE_TYPE_PRIMARY ? "PRIMARY" : "OVERLAY",
597 m_useZpos);
598 }
599
600#ifdef USE_GLES
602 return 0;
603
604 // init gbm
606 LOGERROR("drmdevice: %s: failed to init gbm device and surface!", __FUNCTION__);
607 return -1;
608 }
609
610 // init egl
611 if (InitEGL()) {
612 LOGERROR("drmdevice: %s: failed to init egl!", __FUNCTION__);
613 return -1;
614 }
615#endif
616
617 return 0;
618}
619
620#ifdef USE_GLES
633{
635 if (!m_pGbmDevice) {
636 LOGERROR("drmdevice: %s: failed to create gbm device!", __FUNCTION__);
637 return -1;
638 }
639
641 if (!m_pGbmSurface) {
642 LOGERROR("drmdevice: %s: failed to create %d x %d surface bo", __FUNCTION__, w, h);
643 return -1;
644 }
645
646 return 0;
647}
648
651
654{
657};
658
665{
667 EGL_BUFFER_SIZE, 32,
673 };
674 EGLConfig *configs = nullptr;
675 EGLint matched = 0;
676 EGLint count = 0;
678 if (count < 1)
679 LOGFATAL("drmdevice: %s: no EGL configs to choose from", __FUNCTION__);
680
681 LOGDEBUG2(L_OPENGL, "drmdevice: %s: %d EGL configs found", __FUNCTION__, count);
682
683 configs = (EGLConfig *)malloc(count * sizeof(*configs));
684 if (!configs)
685 LOGFATAL("drmdevice: %s: can't allocate space for EGL configs", __FUNCTION__);
686
688 if (!matched) {
689 free(configs);
690 LOGFATAL("drmdevice: %s: no EGL configs with appropriate attributes", __FUNCTION__);
691 }
692
693 LOGDEBUG2(L_OPENGL, "drmdevice: %s: %d appropriate EGL configs found, which match attributes", __FUNCTION__, matched);
694
696 for (int i = 0; i < matched; ++i) {
699
701 chosen = configs[i];
702 break;
703 }
704 }
705
706 free(configs);
707 if (chosen == NULL)
708 LOGFATAL("drmdevice: %s: no matching gbm config found", __FUNCTION__);
709
710 return chosen;
711}
712
720{
722
727
729 if (!m_eglDisplay) {
730 LOGERROR("drmdevice: %s: failed to get eglDisplay", __FUNCTION__);
731 return -1;
732 }
733
735 LOGERROR("drmdevice: %s: eglInitialize failed", __FUNCTION__);
736 return -1;
737 }
738
739 LOGDEBUG2(L_OPENGL, "drmdevice: %s: Using display %p with EGL version %d.%d", __FUNCTION__, m_eglDisplay, iMajorVersion, iMinorVersion);
744
746
749 if (!m_eglContext) {
750 LOGERROR("drmdevice: %s: failed to create eglContext", __FUNCTION__);
751 return -1;
752 }
753
756 LOGERROR("drmdevice: %s: failed to create eglSurface", __FUNCTION__);
757 return -1;
758 }
759
763
764 LOGDEBUG2(L_OPENGL, "drmdevice: %s: GLSurface %p on EGLDisplay %p for %d x %d BO created", __FUNCTION__, m_eglSurface, m_eglDisplay, s_width, s_height);
765
766 m_glInitiated = true;
767 LOGINFO("DRM Setup: EGL context initialized");
768
769 return 0;
770}
771
777static void drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
778{
780 cDrmBuffer *buf = (cDrmBuffer *)data;
781
782 if (buf->Id())
783 drmModeRmFB(drm_fd, buf->Id());
784
785 delete(buf);
786}
787
790
791__attribute__ ((weak)) int
792gbm_bo_get_fd(struct gbm_bo *bo);
793
796
797__attribute__ ((weak)) int
799
802
804gbm_bo_get_offset(struct gbm_bo *bo, int plane);
805
814{
817 int ret = -1;
818
819 // the buffer was already allocated
820 if (buf)
821 return buf;
822
824
828 uint64_t modifiers[4] = {0};
830 const int num_planes = gbm_bo_get_plane_count(bo);
831 buf->SetNumPlanes(num_planes);
832 for (int i = 0; i < num_planes; i++) {
833 buf->SetHandle(i, gbm_bo_get_handle_for_plane(bo, i).u32);
834 buf->SetPitch(i, gbm_bo_get_stride_for_plane(bo, i));
835 buf->SetOffset(i, gbm_bo_get_offset(bo, i));
836 modifiers[i] = modifiers[0];
837 buf->SetSize(i, buf->Height() * buf->Pitch(i));
838 LOGDEBUG2(L_DRM, "drmdevice: %s: %d: handle %d pitch %d, offset %d, size %d", __FUNCTION__, i, buf->PrimeHandle(i), buf->Pitch(i), buf->Offset(i), buf->Size(i));
839 }
840 buf->SetNumObjects(1);
841 buf->SetObjectIndex(0, 0);
842 buf->SetDmaBufHandle(gbm_bo_get_fd(bo));
843
844 if (modifiers[0]) {
846 LOGDEBUG2(L_DRM, "drmdevice: %s: Using modifier %" PRIx64 "", __FUNCTION__, modifiers[0]);
847 }
848
849 uint32_t id;
850 // Add FB
851 ret = drmModeAddFB2WithModifiers(m_fdDrm, buf->Width(), buf->Height(), buf->PixFmt(),
852 buf->PrimeHandle(), buf->Pitch(), buf->Offset(), modifiers, &id, mod_flags);
853 buf->SetId(id);
854 }
855
856 if (ret) {
857 if (mod_flags)
858 LOGDEBUG2(L_DRM, "drmdevice: %s: Modifiers failed!", __FUNCTION__);
859
860 buf->SetNumPlanes(1);
861 uint32_t tmpHandle[4] = { gbm_bo_get_handle(bo).u32, 0, 0, 0};
862 uint32_t tmpStride[4] = { gbm_bo_get_stride(bo), 0, 0, 0};
863 uint32_t tmpSize[4] = { buf->Height() * buf->Width() * buf->Pitch(0), 0, 0, 0};
864 memcpy(buf->PrimeHandle(), tmpHandle, sizeof(tmpHandle));
865 memcpy(buf->Pitch(), tmpStride, sizeof(tmpStride));
866 memcpy(buf->Size(), tmpSize, sizeof(tmpSize));
867 memset(buf->Offset(), 0, 16);
868 buf->SetNumObjects(1);
869 buf->SetObjectIndex(0, 0);
870 buf->SetDmaBufHandle(gbm_bo_get_fd(bo));
871
872 uint32_t id;
873 ret = drmModeAddFB2(m_fdDrm, buf->Width(), buf->Height(), buf->PixFmt(),
874 buf->PrimeHandle(), buf->Pitch(), buf->Offset(), &id, 0);
875 buf->SetId(id);
876 }
877
878 if (ret) {
879 LOGFATAL("drmdevice: %s: cannot create framebuffer (%d): %m", __FUNCTION__, errno);
880 delete buf;
881 return NULL;
882 }
883
884 uint32_t pixFmt = buf->PixFmt();
885 LOGDEBUG2(L_DRM, "drmdevice: %s: New GL buffer %d x %d pix_fmt %4.4s fb_id %d", __FUNCTION__,
886 buf->Width(), buf->Height(), (char *)&pixFmt, buf->Id());
887
889 return buf;
890}
891#endif
892
904{
905 int i;
906
907 for (i = 0; i < resources->count_crtcs; i++) {
908 const uint32_t crtc_mask = 1 << i;
909 const uint32_t crtc_id = resources->crtcs[i];
910 if (encoder->possible_crtcs & crtc_mask) {
911 return crtc_id;
912 }
913 }
914
915 return -1;
916}
917
927{
928 int i;
929
930 for (i = 0; i < connector->count_encoders; i++) {
931 const uint32_t encoder_id = connector->encoders[i];
933
934 if (encoder) {
937 if (crtc_id != 0) {
938 return crtc_id;
939 }
940 }
941 }
942
943 return -1;
944}
945
950{
951 LOGDEBUG2(L_DRM, "drmdevice: %s: closing fd %d", __FUNCTION__, m_fdDrm);
953
954 close(m_fdDrm);
955 m_fdDrm = -1;
956}
957
975
989 const char *propName, uint64_t value)
990{
991 uint32_t i;
992 uint64_t id = 0;
996
997 for (i = 0; i < objectProps->count_props; i++) {
998 if ((Prop = drmModeGetProperty(m_fdDrm, objectProps->props[i])) == NULL)
999 LOGDEBUG2(L_DRM, "drmdevice: %s: Unable to query property", __FUNCTION__);
1000
1001 if (strcmp(propName, Prop->name) == 0) {
1002 id = Prop->prop_id;
1004 break;
1005 }
1006
1008 }
1009
1011
1012 if (id == 0)
1013 LOGDEBUG2(L_DRM, "drmdevice: %s Unable to find value for property \'%s\'.", __FUNCTION__, propName);
1014
1016}
1017
1030{
1031 uint32_t i;
1032 int found = 0;
1036
1037 if (!objectProps)
1038 return -1;
1039
1040 for (i = 0; i < objectProps->count_props; i++) {
1041 if ((Prop = drmModeGetProperty(m_fdDrm, objectProps->props[i])) == NULL)
1042 LOGDEBUG2(L_DRM, "drmdevice: %s: Unable to query property", __FUNCTION__);
1043
1044 if (strcmp(propName, Prop->name) == 0) {
1045 *value = objectProps->prop_values[i];
1046 found = 1;
1047 }
1048
1050
1051 if (found)
1052 break;
1053 }
1054
1056
1057 if (!found) {
1058 LOGDEBUG2(L_DRM, "drmdevice: %s: Unable to find value for property \'%s\'.", __FUNCTION__, propName);
1059 return -1;
1060 }
1061
1062 return 0;
1063}
1064
1075{
1076 uint32_t i;
1077 int found = 0;
1078 int value = 0;
1079
1083
1084 if (!objectProps)
1085 return 0;
1086
1087 for (i = 0; i < objectProps->count_props; i++) {
1088 if ((Prop = drmModeGetProperty(m_fdDrm, objectProps->props[i])) == NULL)
1089 LOGDEBUG2(L_DRM, "drmdevice: %s: Unable to query property", __FUNCTION__);
1090
1091 if (strcmp(propName, Prop->name) == 0) {
1092 value = objectProps->props[i];
1093 found = 1;
1094 }
1095
1097
1098 if (found)
1099 break;
1100 }
1101
1103
1104 if (!found)
1105 LOGDEBUG2(L_DRM, "drmdevice: %s: Unable to find value for property \'%s\'.", __FUNCTION__, propName);
1106
1107 return value;
1108}
1109
1117
1129
1137{
1139}
1140
1145{
1146 memset(&m_drmEventCtx, 0, sizeof(m_drmEventCtx));
1147 m_drmEventCtx.version = 2;
1148}
1149
1150/*
1151 * drmModeAtomic* wrapper functions
1152 */
1157
1162
1167
1172
1177
1182
1187
1192
1197
1202
1204{
1205 int ret = drmModeCreatePropertyBlob(m_fdDrm, data, size, blobID);
1206 if (ret)
1207 LOGDEBUG2(L_DRM, "drmdevice: %s: failed to create hdr property blob: id %d, data %p (%d) ret %d", __FUNCTION__, blobID, data, size, ret);
1208
1209 return ret;
1210}
1211
1213{
1215 if (ret)
1216 LOGDEBUG2(L_DRM, "drmdevice: %s: failed to set hdr property blob: blob id %d connector_id %d, m_hdrMetadata %d ret %d",
1218
1219 return ret;
1220}
1221
DRM Buffer.
Definition drmbuffer.h:46
bool m_glInitiated
true, if OpenGL/ES context is initiated
Definition drmdevice.h:140
uint32_t m_userReqDisplayRefreshRate
user requested display refresh rate
Definition drmdevice.h:117
int SetConnectorHdrOutputMetadata(drmModeAtomicReqPtr, uint32_t)
int m_userReqDisplayHeight
user requested display height
Definition drmdevice.h:116
drmModeModeInfo m_drmModeInfo
mode info
Definition drmdevice.h:107
cDrmBuffer * GetBufFromBo(struct gbm_bo *)
Get a drm buffer from a gbm buffer object.
int GetPropertyValue(uint32_t, uint32_t, const char *, uint64_t *)
Get a drm property value.
int SetConnectorColorspace(drmModeAtomicReqPtr, uint32_t)
int InitEGL(void)
Init EGL context.
int CreateModeBlob(uint32_t *)
int CreatePropertyBlob(uint32_t *)
Wrapper to create a property blob.
uint32_t m_hdrMetadata
property id of HDR_OUTPUT_METADATA
Definition drmdevice.h:110
int GetVideoPlaneColorRange(uint64_t *)
cDrmPlane m_videoPlane
the video drm plane
Definition drmdevice.h:122
int DestroyHdrBlob(uint32_t)
struct gbm_surface * m_pGbmSurface
pointer to the gbm surface
Definition drmdevice.h:135
uint32_t GetPropertyID(uint32_t, uint32_t, const char *)
Get a property ID.
int SetVideoPlaneColorEncoding(drmModeAtomicReqPtr, uint32_t)
EGLContext m_eglContext
EGL context.
Definition drmdevice.h:139
int SetPropertyRequest(drmModeAtomicReqPtr, uint32_t, uint32_t, const char *, uint64_t)
Add a drm property to an atomic modeset request.
int SetCrtcModeId(drmModeAtomicReqPtr, uint32_t)
int32_t FindCrtcForConnector(const drmModeRes *, const drmModeConnector *)
Find the CRTC_ID for the given connector.
EGLSurface m_eglSurface
EGL surface.
Definition drmdevice.h:137
int HandleEvent(void)
Poll for a drm event.
int m_userReqDisplayWidth
user requested display width
Definition drmdevice.h:115
int DestroyModeBlob(uint32_t)
cDrmPlane m_pipPlane
the pip drm plane
Definition drmdevice.h:125
drmModeCrtc * m_drmModeCrtcSaved
saved CRTC infos
Definition drmdevice.h:111
int CreateHdrBlob(struct hdr_output_metadata *, size_t, uint32_t *)
int m_fdDrm
drm file descriptor
Definition drmdevice.h:105
uint64_t m_zposPip
zpos of pip plane
Definition drmdevice.h:124
int SetConnectorHdrBlobProperty(uint32_t)
EGLDisplay m_eglDisplay
EGL display.
Definition drmdevice.h:138
void SaveCrtc(void)
Save information of a CRTC.
~cDrmDevice(void)
Definition drmdevice.cpp:55
uint32_t m_connectorId
connector id
Definition drmdevice.h:106
void RestoreCrtc(void)
Restore information of a CRTC.
void Close(void)
Close the drm file handle.
uint32_t m_crtcId
current crtc ID
Definition drmdevice.h:108
int SetConnectorCrtcId(drmModeAtomicReqPtr)
int InitGbm(int, int, uint32_t, uint64_t)
Init gbm device and surface.
uint32_t m_crtcIndex
current crtc index
Definition drmdevice.h:109
int SetCrtcActive(drmModeAtomicReqPtr, uint32_t)
cVideoRender * m_pRender
pointer to cVideoRender object
Definition drmdevice.h:103
int Init(void)
Initiate the drm device.
uint64_t m_zposPrimary
zpos of primary plane
Definition drmdevice.h:121
cDrmDevice(cVideoRender *, const char *, const char *)
Create a drm device.
Definition drmdevice.cpp:47
drmEventContext m_drmEventCtx
drm event context
Definition drmdevice.h:112
bool m_useZpos
is set, if drm hardware can use zpos
Definition drmdevice.h:119
struct gbm_device * m_pGbmDevice
pointer to the gbm device
Definition drmdevice.h:134
cDrmPlane m_osdPlane
the osd drm plane
Definition drmdevice.h:123
int SetVideoPlaneColorRange(drmModeAtomicReqPtr, uint32_t)
void InitEvent(void)
Init the event context.
const char * m_userDrmDevice
user requested drm device
Definition drmdevice.h:114
uint64_t m_zposOverlay
zpos of overlay plane
Definition drmdevice.h:120
DRM Plane.
Definition drmplane.h:23
uint64_t GetType(void)
Definition drmplane.h:41
uint64_t GetZpos(void)
Definition drmplane.h:53
void SetId(uint32_t id)
Definition drmplane.h:40
int HasZpos(int)
Check, if the plane is able to set the zpos property.
Definition drmplane.cpp:179
void FillProperties(int)
Fill the plane properties.
Definition drmplane.cpp:34
void SetZpos(uint64_t zpos)
Definition drmplane.h:54
void SetType(uint64_t type)
Definition drmplane.h:42
uint32_t GetId(void)
Definition drmplane.h:39
Video Renderer.
bool OglOsdDisabled(void)
void SetScreenSize(int, int, double)
Wrapper to set the screen size in the device.
int plane
PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display
static int TestCaps(int fd)
Test drm capabilities.
Definition drmdevice.cpp:77
PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC get_platform_surface
__attribute__((weak)) union gbm_bo_handle gbm_bo_get_handle_for_plane(struct gbm_bo *bo
DRM Device Header File.
DRM Plane Header File.
static void drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
Callback function to destroy a drm buffer which stays in the gbm_bo's user data.
EGLConfig GetEGLConfig(void)
Get a suitable EGLConfig.
static int FindDrmDevice(drmModeRes **resources)
Find and open a suitable device with the wanted capabilities.
static int32_t FindCrtcForEncoder(const drmModeRes *resources, const drmModeEncoder *encoder)
Find the CRTC_ID for the given encoder.
static int get_resources(int fd, drmModeRes **resources)
Definition drmdevice.cpp:61
static const EGLint context_attribute_list[]
static int OpenDrmDevice(const char *device, drmModeRes **resources)
Open the given device.
static drmModeConnector * FindDrmConnector(int fd, drmModeRes *resources)
Find a suitable connector, preferably a connected one.
#define LOGDEBUG2
log to LOG_DEBUG and add a prefix
Definition logger.h:47
#define LOGERROR
log to LOG_ERR
Definition logger.h:39
#define LOGWARNING
log to LOG_WARN
Definition logger.h:41
#define LOGINFO
log to LOG_INFO
Definition logger.h:43
#define LOGFATAL
log to LOG_ERR and abort
Definition logger.h:37
#define EGL_CHECK(stmt)
eglCheckError macro
Definition misc.h:62
@ L_DRM
drm logs
Definition logger.h:60
@ L_OPENGL
opengl osd logs
Definition logger.h:65
Logger Header File.
Video Renderer (Display) Header File.