vdr-plugin-softhddevice-drm-gles 1.6.2
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
60
62{
63 LOGDEBUG2(L_DRM, "drmdevice: %s", __FUNCTION__);
64}
65
67{
69 if (*resources == NULL) {
70 LOGERROR("drmdevice: %s: cannot retrieve DRM resources (%d): %m", __FUNCTION__, errno);
71 return -1;
72 }
73 return 0;
74}
75
82static int TestCaps(int fd)
83{
85
86 if (drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &test) < 0 || test == 0)
87 return 1;
88
90 return 1;
91
93 return 1;
94
95 if (drmGetCap(fd, DRM_CAP_PRIME, &test) < 0)
96 return 1;
97
99 return 1;
100
102 return 1;
103
104 return 0;
105}
106
107#define MAX_DRM_DEVICES 64
114{
116 int num_devices, fd = -1;
117
119 if (num_devices < 0) {
120 LOGERROR("drmdevice: %s: drmGetDevices2 failed: %s", __FUNCTION__, strerror(-num_devices));
121 return fd;
122 }
123
124 for (int i = 0; i < num_devices && fd < 0; i++) {
125 drmDevicePtr device = devices[i];
126 int ret;
127
128 if (!(device->available_nodes & (1 << DRM_NODE_PRIMARY)))
129 continue;
130 fd = open(device->nodes[DRM_NODE_PRIMARY], O_RDWR);
131 if (fd < 0)
132 continue;
133
134 if (TestCaps(fd)) {
135 close(fd);
136 fd = -1;
137 continue;
138 }
139
141 if (!ret)
142 break;
143 close(fd);
144 fd = -1;
145 }
147
148 if (fd < 0)
149 LOGERROR("drmdevice: %s: no drm device found!", __FUNCTION__);
150
151 return fd;
152}
153
158{
160 int i;
161
162 // search for a connected connector
163 for (i = 0; i < resources->count_connectors; i++) {
164 connector = drmModeGetConnector(fd, resources->connectors[i]);
165 if (connector && connector->connection == DRM_MODE_CONNECTED)
166 return connector;
168 connector = NULL;
169 }
170
171 // search for a not connected connector, but with available modes
172 // this is a workaround for RPI: in case we don't have a monitor connected
173 // we can load an edid file at boot time, where the available modes are listed.
174 // To bring softhddevice up, we also have to go through the not connected connectors
175 for (i = 0; i < resources->count_connectors; i++) {
176 connector = drmModeGetConnector(fd, resources->connectors[i]);
177 if (connector && connector->count_modes > 0)
178 return connector;
180 connector = NULL;
181 }
182
183 // we couldn't find a connector
184 return connector;
185}
186
187
195{
202 int i;
203 uint32_t j, k;
204
205 // find a drm device
207 if (m_fdDrm < 0) {
208 LOGERROR("drmdevice: %s: Could not open device!", __FUNCTION__);
209 return -1;
210 }
211
212 LOGDEBUG2(L_DRM, "drmdevice: %s: fd: %d DRM have %i connectors, %i crtcs, %i encoders", __FUNCTION__,
213 m_fdDrm, resources->count_connectors, resources->count_crtcs,
214 resources->count_encoders);
215
216 // find a connector
218 if (!connector) {
219 LOGERROR("drmdevice: %s: cannot retrieve DRM connector (%d): %m", __FUNCTION__, errno);
220 return -errno;
221 }
222 m_connectorId = connector->connector_id;
223
224 // find a user requested mode
226 for (i = 0; i < connector->count_modes; i++) {
231 LOGDEBUG2(L_DRM, "drmdevice: %s: Use user requested mode: %dx%d@%d", __FUNCTION__, drmmode->hdisplay, drmmode->vdisplay, drmmode->vrefresh);
232 break;
233 }
234 }
235 if (!drmmode)
236 LOGWARNING("drmdevice: %s: User requested mode not found, try default modes", __FUNCTION__);
237 }
238
239 uint32_t preferred_hz[3] = {50, 60, 0};
240
241 // find the highest resolution mode with 50, 60 or any refresh rate
242 if (!drmmode) {
243 j = 0;
244 int width;
245 while (!drmmode && preferred_hz[j]) {
246 for (i = 0, width = 0; i < connector->count_modes; i++) {
248 if (preferred_hz[j] && current_mode->vrefresh != preferred_hz[j])
249 continue;
250
251 int current_width = current_mode->hdisplay;
252 if (current_width > width) {
254 width = current_width;
255 }
256 }
257 j++;
258 }
259
260 if (drmmode)
261 LOGDEBUG2(L_DRM, "drmdevice: %s: Use mode with the biggest width: %dx%d@%d", __FUNCTION__,
262 drmmode->hdisplay, drmmode->vdisplay, drmmode->vrefresh);
263 }
264
265 if (!drmmode) {
266 LOGERROR("drmdevice: %s: No monitor mode found! Probably no monitor connected, giving up!", __FUNCTION__);
267 return -1;
268 }
269
271
272 // find encoder
273 for (i = 0; i < resources->count_encoders; i++) {
275 if (encoder->encoder_id == connector->encoder_id)
276 break;
278 encoder = NULL;
279 }
280
281 if (encoder) {
282 m_crtcId = encoder->crtc_id;
283 LOGDEBUG2(L_DRM, "drmdevice: %s: have encoder, m_crtcId %d", __FUNCTION__, m_crtcId);
284 } else {
286 if (crtc_id == -1) {
287 LOGERROR("drmdevice: %s: No crtc found!", __FUNCTION__);
288 return -errno;
289 }
290
292 LOGDEBUG2(L_DRM, "drmdevice: %s: have no encoder, m_crtcId %d", __FUNCTION__, m_crtcId);
293 }
294
295 for (i = 0; i < resources->count_crtcs; i++) {
296 if (resources->crtcs[i] == m_crtcId) {
297 m_crtcIndex = i;
298 break;
299 }
300 }
301
303 if (m_hdrMetadata != 0)
304 LOGDEBUG2(L_DRM, "drmdevice: %s: HDR output metadata ID %d in connector %d", __FUNCTION__, m_hdrMetadata, m_connectorId);
305
306 // Calculate the refresh rate. Don't use m_drmModeInfo.vrefresh, because we need the precise value.
307 double refreshRateHz = (double)m_drmModeInfo.clock * 1000.0 / ((double)m_drmModeInfo.htotal * (double)m_drmModeInfo.vtotal);
308
310
311 LOGINFO("DRM Setup: Using Monitor Mode %dx%d@%.2fHz, m_crtcId %d crtc_idx %d",
313
315
316
317 // find planes
319 LOGERROR("drmdevice: %s: cannot retrieve PlaneResources (%d): %m", __FUNCTION__, errno);
320 return -1;
321 }
322
323 // test and list the local planes
324 cDrmPlane best_primary_video_plane; // NV12 capable primary plane with the lowest plane_id
325 cDrmPlane best_overlay_video_plane; // NV12 capable overlay plane with the lowest plane_id
326 cDrmPlane best_primary_osd_plane; // AR24 capable primary plane with the highest plane_id
327 cDrmPlane best_overlay_osd_plane; // AR24 capable overlay plane with the highest plane_id
328
329 // collect candidates for pip (NV12 overlay plane). The best one is chosen after we decided which
330 // planes are used for video and osd
331 std::vector<cDrmPlane> overlayNV12Candidates;
332
333 for (j = 0; j < planeRes->count_planes; j++) {
335
336 if (plane == NULL) {
337 LOGERROR("drmdevice: %s: cannot query DRM-KMS plane %d", __FUNCTION__, j);
338 continue;
339 }
340
341 uint64_t type = 0;
342 uint64_t zpos = 0;
343 char pixelformats[256];
344
345 if (plane->possible_crtcs & (1 << m_crtcIndex)) {
346 if (GetPropertyValue(planeRes->planes[j], DRM_MODE_OBJECT_PLANE, "type", &type)) {
347 LOGDEBUG2(L_DRM, "drmdevice: %s: Failed to get property 'type'", __FUNCTION__);
348 }
349 if (GetPropertyValue(planeRes->planes[j], DRM_MODE_OBJECT_PLANE, "zpos", &zpos)) {
350 LOGDEBUG2(L_DRM, "drmdevice: %s: Failed to get property 'zpos'", __FUNCTION__);
351 } else {
352 m_useZpos = true;
353 }
354
355 LOGDEBUG2(L_DRM, "drmdevice: %s: %s: id %i possible_crtcs %i", __FUNCTION__,
356 (type == DRM_PLANE_TYPE_PRIMARY) ? "PRIMARY " :
357 (type == DRM_PLANE_TYPE_OVERLAY) ? "OVERLAY " :
358 (type == DRM_PLANE_TYPE_CURSOR) ? "CURSOR " : "UNKNOWN",
359 plane->plane_id, plane->possible_crtcs);
360 strcpy(pixelformats, " ");
361
362 // test pixel format and plane caps
363 for (k = 0; k < plane->count_formats; k++) {
364 if (encoder->possible_crtcs & plane->possible_crtcs) {
365 char tmp[10];
366 switch (plane->formats[k]) {
367 case DRM_FORMAT_NV12:
368 snprintf(tmp, sizeof(tmp), " %4.4s", (char *)&plane->formats[k]);
370 if (type == DRM_PLANE_TYPE_PRIMARY && !best_primary_video_plane.GetId()) {
371 best_primary_video_plane.SetId(plane->plane_id);
372 best_primary_video_plane.SetType(type);
374 strcat(pixelformats, "! ");
375 }
376 if (type == DRM_PLANE_TYPE_OVERLAY && !best_overlay_video_plane.GetId()) {
377 best_overlay_video_plane.SetId(plane->plane_id);
378 best_overlay_video_plane.SetType(type);
380 strcat(pixelformats, "! ");
381 }
382 // store overlay NV12 plane as a candidate for pip
383 if (type == DRM_PLANE_TYPE_OVERLAY) {
385 cand.SetId(plane->plane_id);
386 cand.SetType(type);
387 cand.SetZpos(zpos);
388 overlayNV12Candidates.push_back(cand);
389 }
390 break;
392 snprintf(tmp, sizeof(tmp), " %4.4s", (char *)&plane->formats[k]);
394 if (type == DRM_PLANE_TYPE_PRIMARY) {
395 best_primary_osd_plane.SetId(plane->plane_id);
396 best_primary_osd_plane.SetType(type);
398 strcat(pixelformats, "! ");
399 }
400 if (type == DRM_PLANE_TYPE_OVERLAY) {
401 best_overlay_osd_plane.SetId(plane->plane_id);
402 best_overlay_osd_plane.SetType(type);
404 strcat(pixelformats, "! ");
405 }
406 break;
407 default:
408 break;
409 }
410 }
411 }
412 LOGDEBUG2(L_DRM, "drmdevice: %s", __FUNCTION__, pixelformats);
413 }
415 }
416
417 // See which planes we should use for video and osd
418 if (best_primary_video_plane.GetId() && best_overlay_osd_plane.GetId()) {
427 } else if (best_overlay_video_plane.GetId() && best_primary_osd_plane.GetId()) {
436 m_useZpos = true;
437 } else {
438 LOGERROR("drmdevice: %s: No suitable planes found!", __FUNCTION__);
439 return -1;
440 }
441
442 // now pick the best pip plane from the NV12 overlay candidates we collected above
445 uint32_t pid = cand.GetId();
446 if (pid == m_videoPlane.GetId() || pid == m_osdPlane.GetId())
447 continue;
448 if (!best_overlay_pip_plane.GetId() || pid > best_overlay_pip_plane.GetId()) {
450 }
451 }
452
453 if (best_overlay_pip_plane.GetId()) {
458 } else {
459 LOGWARNING("drmdevice: %s: No suitable plane for Picture-in-Picture found. PIP will be disabled.", __FUNCTION__);
460 }
461
462 // debug output
463 if (best_primary_video_plane.GetId()) {
464 LOGDEBUG2(L_DRM, "drmdevice: %s: best_primary_video_plane: plane_id %d, type %s, zpos %" PRIu64 "", __FUNCTION__,
465 best_primary_video_plane.GetId(), best_primary_video_plane.GetType() == DRM_PLANE_TYPE_PRIMARY ? "PRIMARY" : "OVERLAY", best_primary_video_plane.GetZpos());
466 }
467 if (best_overlay_video_plane.GetId()) {
468 LOGDEBUG2(L_DRM, "drmdevice: %s: best_overlay_video_plane: plane_id %d, type %s, zpos %" PRIu64 "", __FUNCTION__,
469 best_overlay_video_plane.GetId(), best_overlay_video_plane.GetType() == DRM_PLANE_TYPE_PRIMARY ? "PRIMARY" : "OVERLAY", best_overlay_video_plane.GetZpos());
470 }
471 if (best_primary_osd_plane.GetId()) {
472 LOGDEBUG2(L_DRM, "drmdevice: %s: best_primary_osd_plane: plane_id %d, type %s, zpos %" PRIu64 "", __FUNCTION__,
473 best_primary_osd_plane.GetId(), best_primary_osd_plane.GetType() == DRM_PLANE_TYPE_PRIMARY ? "PRIMARY" : "OVERLAY", best_primary_osd_plane.GetZpos());
474 }
475 if (best_overlay_osd_plane.GetId()) {
476 LOGDEBUG2(L_DRM, "drmdevice: %s: best_overlay_osd_plane: plane_id %d, type %s, zpos %" PRIu64 "", __FUNCTION__,
477 best_overlay_osd_plane.GetId(), best_overlay_osd_plane.GetType() == DRM_PLANE_TYPE_PRIMARY ? "PRIMARY" : "OVERLAY", best_overlay_osd_plane.GetZpos());
478 }
479 if (best_overlay_pip_plane.GetId()) {
480 LOGDEBUG2(L_DRM, "drmdevice: %s: best_overlay_pip_plane: plane_id %d, type %s, zpos %" PRIu64 "", __FUNCTION__,
481 best_overlay_pip_plane.GetId(), best_overlay_pip_plane.GetType() == DRM_PLANE_TYPE_PRIMARY ? "PRIMARY" : "OVERLAY", best_overlay_pip_plane.GetZpos());
482 }
483
484 // fill the plane's properties to speed up SetPropertyRequest later
487
488 if (m_pipPlane.GetId())
490
491 // Check, if we can set z-order (meson and rpi have fixed z-order, which cannot be changed)
493 m_useZpos = false;
494 }
496 m_useZpos = false;
497 }
499 m_useZpos = false;
500 }
501
502 // m_useZpos was set, if video is on OVERLAY, and osd is on PRIMARY
503 // Check if the OVERLAY plane really got a higher zpos than the PRIMARY plane
504 // If not, change their zpos values or hardcode them to
505 // 1 OVERLAY (Video)
506 // 0 PRIMARY (Osd)
508 char str_zpos[256];
509 strcpy(str_zpos, "drmdevice: Init: zpos values are wrong, so ");
511 // is this possible?
512 strcat(str_zpos, "hardcode them to 0 and 1, because they are equal");
513 m_zposPrimary = 0;
514 m_zposOverlay = 1;
515 } else {
516 strcat(str_zpos, "switch them");
520 }
521 LOGDEBUG2(L_DRM, "%s", str_zpos);
522 }
523
524 if (drmSetMaster(m_fdDrm) < 0) {
525 LOGDEBUG2(L_DRM, "drmdevice: Failed to set drm master, try authorize instead: {}", strerror(errno));
526
528 if (drmGetMagic(m_fdDrm, &magic) < 0)
529 LOGFATAL("drmdevice: Failed to get drm magic: {}", strerror(errno));
530
531 if (drmAuthMagic(m_fdDrm, magic) < 0)
532 LOGFATAL("drmdevice: Failed to authorize drm magic: {}", strerror(errno));
533 }
534
538
539 if (m_pipPlane.GetId()) {
540 LOGINFO("DRM setup - CRTC: %i video_plane: %i (%s %" PRIu64 ") osd_plane: %i (%s %" PRIu64 ") pip_plane: %i (%s %" PRIu64 ") m_useZpos: %d",
541 m_crtcId,
543 m_videoPlane.GetType() == DRM_PLANE_TYPE_PRIMARY ? "PRIMARY" : "OVERLAY",
546 m_osdPlane.GetType() == DRM_PLANE_TYPE_PRIMARY ? "PRIMARY" : "OVERLAY",
549 m_pipPlane.GetType() == DRM_PLANE_TYPE_PRIMARY ? "PRIMARY" : "OVERLAY",
551 m_useZpos);
552 } else {
553 LOGINFO("DRM setup - CRTC: %i video_plane: %i (%s %" PRIu64 ") osd_plane: %i (%s %" PRIu64 ") m_useZpos: %d (pip disbled)",
554 m_crtcId,
556 m_videoPlane.GetType() == DRM_PLANE_TYPE_PRIMARY ? "PRIMARY" : "OVERLAY",
559 m_osdPlane.GetType() == DRM_PLANE_TYPE_PRIMARY ? "PRIMARY" : "OVERLAY",
561 m_useZpos);
562 }
563
564#ifdef USE_GLES
566 return 0;
567
568 // init gbm
570 LOGERROR("drmdevice: %s: failed to init gbm device and surface!", __FUNCTION__);
571 return -1;
572 }
573
574 // init egl
575 if (InitEGL()) {
576 LOGERROR("drmdevice: %s: failed to init egl!", __FUNCTION__);
577 return -1;
578 }
579#endif
580
581 return 0;
582}
583
584#ifdef USE_GLES
597{
599 if (!m_pGbmDevice) {
600 LOGERROR("drmdevice: %s: failed to create gbm device!", __FUNCTION__);
601 return -1;
602 }
603
605 if (!m_pGbmSurface) {
606 LOGERROR("drmdevice: %s: failed to create %d x %d surface bo", __FUNCTION__, w, h);
607 return -1;
608 }
609
610 return 0;
611}
612
615
617{
620};
621
626{
628 EGL_BUFFER_SIZE, 32,
634 };
635 EGLConfig *configs = nullptr;
636 EGLint matched = 0;
637 EGLint count = 0;
639 if (count < 1)
640 LOGFATAL("drmdevice: %s: no EGL configs to choose from", __FUNCTION__);
641
642 LOGDEBUG2(L_OPENGL, "drmdevice: %s: %d EGL configs found", __FUNCTION__, count);
643
644 configs = (EGLConfig *)malloc(count * sizeof(*configs));
645 if (!configs)
646 LOGFATAL("drmdevice: %s: can't allocate space for EGL configs", __FUNCTION__);
647
649 if (!matched) {
650 free(configs);
651 LOGFATAL("drmdevice: %s: no EGL configs with appropriate attributes", __FUNCTION__);
652 }
653
654 LOGDEBUG2(L_OPENGL, "drmdevice: %s: %d appropriate EGL configs found, which match attributes", __FUNCTION__, matched);
655
657 for (int i = 0; i < matched; ++i) {
660
662 chosen = configs[i];
663 break;
664 }
665 }
666
667 free(configs);
668 if (chosen == NULL)
669 LOGFATAL("drmdevice: %s: no matching gbm config found", __FUNCTION__);
670
671 return chosen;
672}
673
681{
683
688
690 if (!m_eglDisplay) {
691 LOGERROR("drmdevice: %s: failed to get eglDisplay", __FUNCTION__);
692 return -1;
693 }
694
696 LOGERROR("drmdevice: %s: eglInitialize failed", __FUNCTION__);
697 return -1;
698 }
699
700 LOGDEBUG2(L_OPENGL, "drmdevice: %s: Using display %p with EGL version %d.%d", __FUNCTION__, m_eglDisplay, iMajorVersion, iMinorVersion);
705
707
710 if (!m_eglContext) {
711 LOGERROR("drmdevice: %s: failed to create eglContext", __FUNCTION__);
712 return -1;
713 }
714
717 LOGERROR("drmdevice: %s: failed to create eglSurface", __FUNCTION__);
718 return -1;
719 }
720
724
725 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);
726
727 m_glInitiated = true;
728 LOGINFO("DRM Setup: EGL context initialized");
729
730 return 0;
731}
732
736static void drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
737{
739 cDrmBuffer *buf = (cDrmBuffer *)data;
740
741 if (buf->Id())
742 drmModeRmFB(drm_fd, buf->Id());
743
744 delete(buf);
745}
746
749
750__attribute__ ((weak)) int
751gbm_bo_get_fd(struct gbm_bo *bo);
752
755
756__attribute__ ((weak)) int
758
761
763gbm_bo_get_offset(struct gbm_bo *bo, int plane);
764
773{
776 int ret = -1;
777
778 // the buffer was already allocated
779 if (buf)
780 return buf;
781
783
787 uint64_t modifiers[4] = {0};
789 const int num_planes = gbm_bo_get_plane_count(bo);
790 buf->SetNumPlanes(num_planes);
791 for (int i = 0; i < num_planes; i++) {
792 buf->SetHandle(i, gbm_bo_get_handle_for_plane(bo, i).u32);
793 buf->SetPitch(i, gbm_bo_get_stride_for_plane(bo, i));
794 buf->SetOffset(i, gbm_bo_get_offset(bo, i));
795 modifiers[i] = modifiers[0];
796 buf->SetSize(i, buf->Height() * buf->Pitch(i));
797 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));
798 }
799 buf->SetNumObjects(1);
800 buf->SetObjectIndex(0, 0);
801 buf->SetDmaBufHandle(gbm_bo_get_fd(bo));
802
803 if (modifiers[0]) {
805 LOGDEBUG2(L_DRM, "drmdevice: %s: Using modifier %" PRIx64 "", __FUNCTION__, modifiers[0]);
806 }
807
808 uint32_t id;
809 // Add FB
810 ret = drmModeAddFB2WithModifiers(m_fdDrm, buf->Width(), buf->Height(), buf->PixFmt(),
811 buf->PrimeHandle(), buf->Pitch(), buf->Offset(), modifiers, &id, mod_flags);
812 buf->SetId(id);
813 }
814
815 if (ret) {
816 if (mod_flags)
817 LOGDEBUG2(L_DRM, "drmdevice: %s: Modifiers failed!", __FUNCTION__);
818
819 buf->SetNumPlanes(1);
820 uint32_t tmpHandle[4] = { gbm_bo_get_handle(bo).u32, 0, 0, 0};
821 uint32_t tmpStride[4] = { gbm_bo_get_stride(bo), 0, 0, 0};
822 uint32_t tmpSize[4] = { buf->Height() * buf->Width() * buf->Pitch(0), 0, 0, 0};
823 memcpy(buf->PrimeHandle(), tmpHandle, sizeof(tmpHandle));
824 memcpy(buf->Pitch(), tmpStride, sizeof(tmpStride));
825 memcpy(buf->Size(), tmpSize, sizeof(tmpSize));
826 memset(buf->Offset(), 0, 16);
827 buf->SetNumObjects(1);
828 buf->SetObjectIndex(0, 0);
829 buf->SetDmaBufHandle(gbm_bo_get_fd(bo));
830
831 uint32_t id;
832 ret = drmModeAddFB2(m_fdDrm, buf->Width(), buf->Height(), buf->PixFmt(),
833 buf->PrimeHandle(), buf->Pitch(), buf->Offset(), &id, 0);
834 buf->SetId(id);
835 }
836
837 if (ret) {
838 LOGFATAL("drmdevice: %s: cannot create framebuffer (%d): %m", __FUNCTION__, errno);
839 delete buf;
840 return NULL;
841 }
842
843 uint32_t pixFmt = buf->PixFmt();
844 LOGDEBUG2(L_DRM, "drmdevice: %s: New GL buffer %d x %d pix_fmt %4.4s fb_id %d", __FUNCTION__,
845 buf->Width(), buf->Height(), (char *)&pixFmt, buf->Id());
846
848 return buf;
849}
850#endif
851
861{
862 int i;
863
864 for (i = 0; i < resources->count_crtcs; i++) {
865 const uint32_t crtc_mask = 1 << i;
866 const uint32_t crtc_id = resources->crtcs[i];
867 if (encoder->possible_crtcs & crtc_mask) {
868 return crtc_id;
869 }
870 }
871
872 return -1;
873}
874
884{
885 int i;
886
887 for (i = 0; i < connector->count_encoders; i++) {
888 const uint32_t encoder_id = connector->encoders[i];
890
891 if (encoder) {
894 if (crtc_id != 0) {
895 return crtc_id;
896 }
897 }
898 }
899
900 return -1;
901}
902
907{
908 LOGDEBUG2(L_DRM, "drmdevice: %s: closing fd %d", __FUNCTION__, m_fdDrm);
910
911 close(m_fdDrm);
912 m_fdDrm = -1;
913}
914
932
946 const char *propName, uint64_t value)
947{
948 uint32_t i;
949 uint64_t id = 0;
953
954 for (i = 0; i < objectProps->count_props; i++) {
955 if ((Prop = drmModeGetProperty(m_fdDrm, objectProps->props[i])) == NULL)
956 LOGDEBUG2(L_DRM, "drmdevice: %s: Unable to query property", __FUNCTION__);
957
958 if (strcmp(propName, Prop->name) == 0) {
959 id = Prop->prop_id;
961 break;
962 }
963
965 }
966
968
969 if (id == 0)
970 LOGDEBUG2(L_DRM, "drmdevice: %s Unable to find value for property \'%s\'.", __FUNCTION__, propName);
971
973}
974
987{
988 uint32_t i;
989 int found = 0;
993
994 if (!objectProps)
995 return -1;
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 *value = objectProps->prop_values[i];
1003 found = 1;
1004 }
1005
1007
1008 if (found)
1009 break;
1010 }
1011
1013
1014 if (!found) {
1015 LOGDEBUG2(L_DRM, "drmdevice: %s: Unable to find value for property \'%s\'.", __FUNCTION__, propName);
1016 return -1;
1017 }
1018
1019 return 0;
1020}
1021
1032{
1033 uint32_t i;
1034 int found = 0;
1035 int value = 0;
1036
1040
1041 if (!objectProps)
1042 return 0;
1043
1044 for (i = 0; i < objectProps->count_props; i++) {
1045 if ((Prop = drmModeGetProperty(m_fdDrm, objectProps->props[i])) == NULL)
1046 LOGDEBUG2(L_DRM, "drmdevice: %s: Unable to query property", __FUNCTION__);
1047
1048 if (strcmp(propName, Prop->name) == 0) {
1049 value = objectProps->props[i];
1050 found = 1;
1051 }
1052
1054
1055 if (found)
1056 break;
1057 }
1058
1060
1061 if (!found)
1062 LOGDEBUG2(L_DRM, "drmdevice: %s: Unable to find value for property \'%s\'.", __FUNCTION__, propName);
1063
1064 return value;
1065}
1066
1074
1086
1094{
1096}
1097
1102{
1103 memset(&m_drmEventCtx, 0, sizeof(m_drmEventCtx));
1104 m_drmEventCtx.version = 2;
1105}
1106
1107/*
1108 * drmModeAtomic* wrapper functions
1109 */
1114
1119
1124
1129
1134
1139
1144
1149
1154
1159
1161{
1162 int ret = drmModeCreatePropertyBlob(m_fdDrm, data, size, blobID);
1163 if (ret)
1164 LOGDEBUG2(L_DRM, "drmdevice: %s: failed to create hdr property blob: id %d, data %p (%d) ret %d", __FUNCTION__, blobID, data, size, ret);
1165
1166 return ret;
1167}
1168
1170{
1172 if (ret)
1173 LOGDEBUG2(L_DRM, "drmdevice: %s: failed to set hdr property blob: blob id %d connector_id %d, m_hdrMetadata %d ret %d",
1175
1176 return ret;
1177}
1178
1183
DRM Buffer.
Definition drmbuffer.h:47
bool m_glInitiated
true, if OpenGL/ES context is initiated
Definition drmdevice.h:137
uint32_t m_userReqDisplayRefreshRate
user requested display refresh rate
Definition drmdevice.h:114
int m_userReqDisplayHeight
user requested display height
Definition drmdevice.h:113
drmModeModeInfo m_drmModeInfo
mode info
Definition drmdevice.h:105
uint32_t m_hdrMetadata
property id of HDR_OUTPUT_METADATA
Definition drmdevice.h:108
cDrmPlane m_videoPlane
the video drm plane
Definition drmdevice.h:119
struct gbm_surface * m_pGbmSurface
pointer to the gbm surface
Definition drmdevice.h:132
EGLContext m_eglContext
EGL context.
Definition drmdevice.h:136
EGLSurface m_eglSurface
EGL surface.
Definition drmdevice.h:134
int m_userReqDisplayWidth
user requested display width
Definition drmdevice.h:112
cDrmPlane m_pipPlane
the pip drm plane
Definition drmdevice.h:122
drmModeCrtc * m_drmModeCrtcSaved
saved CRTC infos
Definition drmdevice.h:109
int m_fdDrm
drm file descriptor
Definition drmdevice.h:103
uint64_t m_zposPip
zpos of pip plane
Definition drmdevice.h:121
EGLDisplay m_eglDisplay
EGL display.
Definition drmdevice.h:135
uint32_t m_connectorId
connector id
Definition drmdevice.h:104
uint32_t m_crtcId
current crtc ID
Definition drmdevice.h:106
uint32_t m_crtcIndex
current crtc index
Definition drmdevice.h:107
cVideoRender * m_pRender
pointer to cVideoRender object
Definition drmdevice.h:101
uint64_t m_zposPrimary
zpos of primary plane
Definition drmdevice.h:118
drmEventContext m_drmEventCtx
drm event context
Definition drmdevice.h:110
bool m_useZpos
is set, if drm hardware can use zpos
Definition drmdevice.h:116
struct gbm_device * m_pGbmDevice
pointer to the gbm device
Definition drmdevice.h:131
cDrmPlane m_osdPlane
the osd drm plane
Definition drmdevice.h:120
uint64_t m_zposOverlay
zpos of overlay plane
Definition drmdevice.h:117
DRM Plane.
Definition drmplane.h:26
uint64_t GetType(void)
Definition drmplane.h:44
uint64_t GetZpos(void)
Definition drmplane.h:56
void SetId(uint32_t id)
Definition drmplane.h:43
void SetZpos(uint64_t zpos)
Definition drmplane.h:57
void SetType(uint64_t type)
Definition drmplane.h:45
uint32_t GetId(void)
Definition drmplane.h:42
Video Renderer.
bool OglOsdDisabled(void)
DRM Device Header File.
DRM Plane Header File.
int SetConnectorHdrOutputMetadata(drmModeAtomicReqPtr, uint32_t)
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 plane
int CreateModeBlob(uint32_t *)
PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display
int CreatePropertyBlob(uint32_t *)
Wrapper to create a property blob.
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.
static int TestCaps(int fd)
Test drm capabilities.
Definition drmdevice.cpp:82
EGLConfig GetEGLConfig(void)
Get a suitable EGLConfig.
static int FindDrmDevice(drmModeRes **resources)
Find and open a suitable device with the wanted capabilities.
int GetVideoPlaneColorRange(uint64_t *)
int DestroyHdrBlob(uint32_t)
uint32_t GetPropertyID(uint32_t, uint32_t, const char *)
Get a property ID.
cDrmDevice(cVideoRender *, const char *)
Create a drm device.
Definition drmdevice.cpp:54
int SetVideoPlaneColorEncoding(drmModeAtomicReqPtr, uint32_t)
static int32_t FindCrtcForEncoder(const drmModeRes *resources, const drmModeEncoder *encoder)
Find the CRTC_ID for the given encoder.
PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC get_platform_surface
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.
int HandleEvent(void)
Poll for a drm event.
static int get_resources(int fd, drmModeRes **resources)
Definition drmdevice.cpp:66
int DestroyModeBlob(uint32_t)
int HasZpos(int)
Check, if the plane is able to set the zpos property.
Definition drmplane.cpp:184
#define MAX_DRM_DEVICES
int CreateHdrBlob(struct hdr_output_metadata *, size_t, uint32_t *)
void FillProperties(int)
Fill the plane properties.
Definition drmplane.cpp:39
int SetConnectorHdrBlobProperty(uint32_t)
void SaveCrtc(void)
Save information of a CRTC.
static const EGLint context_attribute_list[]
~cDrmDevice(void)
Definition drmdevice.cpp:61
void RestoreCrtc(void)
Restore information of a CRTC.
void Close(void)
Close the drm file handle.
int SetConnectorCrtcId(drmModeAtomicReqPtr)
int InitGbm(int, int, uint32_t, uint64_t)
Init gbm device and surface.
int SetCrtcActive(drmModeAtomicReqPtr, uint32_t)
int Init(void)
Initiate the drm device.
static drmModeConnector * FindDrmConnector(int fd, drmModeRes *resources)
Find a suitable connector, preferably a connected one.
__attribute__((weak)) union gbm_bo_handle gbm_bo_get_handle_for_plane(struct gbm_bo *bo
int SetVideoPlaneColorRange(drmModeAtomicReqPtr, uint32_t)
void InitEvent(void)
Init the event context.
#define LOGDEBUG2
log to LOG_DEBUG and add a prefix
Definition logger.h:42
#define LOGERROR
log to LOG_ERR
Definition logger.h:34
#define LOGWARNING
log to LOG_WARN
Definition logger.h:36
#define LOGINFO
log to LOG_INFO
Definition logger.h:38
#define LOGFATAL
log to LOG_ERR and abort
Definition logger.h:32
#define EGL_CHECK(stmt)
eglCheckError macro
Definition misc.h:62
@ L_DRM
drm logs
Definition logger.h:55
@ L_OPENGL
opengl osd logs
Definition logger.h:60
void SetScreenSize(int, int, double)
Wrapper to set the screen size in the device.
Logger Header File.
Video Renderer (Display) Header File.