MythTV master
mythvideodrmbuffer.cpp
Go to the documentation of this file.
1// MythTV
3#include "fourcc.h"
5
6// libdrm
7extern "C" {
8#include <drm_fourcc.h>
9}
10
11#define LOC QString("DRMBuf: ")
12
13static void inline DebugDRMFrame(AVDRMFrameDescriptor* Desc)
14{
15 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString("DRM frame: Layers %1 Objects %2")
16 .arg(Desc->nb_layers).arg(Desc->nb_objects));
17 for (int i = 0; i < Desc->nb_layers; ++i)
18 {
19 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString("Layer %1: Format %2 Planes %3")
20 .arg(i).arg(fourcc_str(static_cast<int>(Desc->layers[i].format)))
21 .arg(Desc->layers[i].nb_planes));
22 for (int j = 0; j < Desc->layers[i].nb_planes; ++j)
23 {
24 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString(" Plane %1: Index %2 Offset %3 Pitch %4")
25 .arg(j).arg(Desc->layers[i].planes[j].object_index)
26 .arg(Desc->layers[i].planes[j].offset).arg(Desc->layers[i].planes[j].pitch));
27 }
28 }
29 for (int i = 0; i < Desc->nb_objects; ++i)
30 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString("Object: %1 FD %2 Mods 0x%3")
31 .arg(i).arg(Desc->objects[i].fd).arg(Desc->objects[i].format_modifier, 0 , 16));
32}
33
34DRMHandle MythVideoDRMBuffer::Create(MythDRMPtr Device, AVDRMFrameDescriptor* DRMDesc, QSize Size)
35{
36 DRMHandle result = std::shared_ptr<MythVideoDRMBuffer>(new MythVideoDRMBuffer(std::move(Device), DRMDesc, Size));
37 if (result->m_valid)
38 return result;
39 return nullptr;
40}
41
42MythVideoDRMBuffer::MythVideoDRMBuffer(MythDRMPtr Device, AVDRMFrameDescriptor* DRMDesc, QSize Size)
43 : m_device(std::move(Device))
44{
45 if (!DRMDesc || DRMDesc->nb_layers < 1)
46 return;
47
48 DebugDRMFrame(DRMDesc);
49
50 // Get GEM handle for each DRM PRIME fd
51 for (auto i = 0; i < DRMDesc->nb_objects; i++)
52 {
53 int ret = drmPrimeFDToHandle(m_device->GetFD(), DRMDesc->objects[i].fd,
54 &m_handles[static_cast<size_t>(i)]);
55 if (ret < 0)
56 {
57 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to get GEM handle");
58 return;
59 }
60 }
61
62 // Get framebuffer
63 DRMArray pitches = { 0 };
64 DRMArray offsets = { 0 };
65 DRMArray handles = { 0 };
66 std::array<uint64_t,4> modifiers = { 0 };
67
68 if (DRMDesc->nb_layers == 1)
69 {
70 const auto * layer = &DRMDesc->layers[0];
71 for (int plane = 0; plane < layer->nb_planes; plane++)
72 {
73 auto objectidx = static_cast<size_t>(layer->planes[plane].object_index);
74 auto handle = m_handles[objectidx];
75 if (handle && layer->planes[plane].pitch)
76 {
77 handles[static_cast<size_t>(plane)] = handle;
78 pitches[static_cast<size_t>(plane)] = static_cast<uint32_t>(layer->planes[plane].pitch);
79 offsets[static_cast<size_t>(plane)] = static_cast<uint32_t>(layer->planes[plane].offset);
80 modifiers[static_cast<size_t>(plane)] = DRMDesc->objects[objectidx].format_modifier;
81 }
82 }
83 }
84 else
85 {
86 // VAAPI exported buffers
87 for (int i = 0; i < DRMDesc->nb_layers; i++)
88 {
89 const auto & layer = DRMDesc->layers[i];
90 auto objectidx = static_cast<size_t>(layer.planes[0].object_index);
91 auto handle = m_handles[objectidx];
92 if (handle && layer.planes[0].pitch)
93 {
94 handles[static_cast<size_t>(i)] = handle;
95 pitches[static_cast<size_t>(i)] = static_cast<uint32_t>(layer.planes[0].pitch);
96 offsets[static_cast<size_t>(i)] = static_cast<uint32_t>(layer.planes[0].offset);
97 modifiers[static_cast<size_t>(i)] = DRMDesc->objects[objectidx].format_modifier;
98 }
99 }
100 }
101
102 uint32_t flags = (modifiers[0] && modifiers[0] != DRM_FORMAT_MOD_INVALID) ? DRM_MODE_FB_MODIFIERS : 0;
103 uint32_t format = DRMDesc->layers[0].format;
104
105 // VAAPI exported buffers. Incomplete.
106 if (DRMDesc->nb_layers == 2)
107 {
108 if (DRMDesc->layers[0].format == DRM_FORMAT_R8 && DRMDesc->layers[1].format == DRM_FORMAT_GR88)
109 format = DRM_FORMAT_NV12;
110 else if (DRMDesc->layers[0].format == DRM_FORMAT_R16 && DRMDesc->layers[1].format == DRM_FORMAT_GR1616)
111 format = DRM_FORMAT_P010;
112 }
113 else if (DRMDesc->nb_layers == 3)
114 {
115
116 }
117
118 // add the video frame FB
119 auto ret = drmModeAddFB2WithModifiers(m_device->GetFD(), static_cast<uint32_t>(Size.width()),
120 static_cast<uint32_t>(Size.height()), format,
121 handles.data(), pitches.data(), offsets.data(),
122 modifiers.data(), &m_fb, flags);
123 if (ret < 0)
124 {
125 // Try without modifiers
126 ret = drmModeAddFB2(m_device->GetFD(), static_cast<uint32_t>(Size.width()),
127 static_cast<uint32_t>(Size.height()), format,
128 handles.data(), pitches.data(), offsets.data(), &m_fb, flags);
129 if (ret < 0)
130 {
131 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Failed to create framebuffer (error: %1)").arg(ret));
132 return;
133 }
134 }
135
136 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString("New video fb %1").arg(m_fb));
137 m_valid = true;
138}
139
141{
142 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString("Deleting video fb %1").arg(m_fb));
143
144 if (m_fb && m_device)
145 drmModeRmFB(m_device->GetFD(), m_fb);
146
147 for (size_t i = 0; i < AV_DRM_MAX_PLANES; ++i)
148 {
149 if (m_handles[i] && m_device)
150 {
151 struct drm_gem_close close = { m_handles[i], 0 };
152 drmIoctl(m_device->GetFD(), DRM_IOCTL_GEM_CLOSE, &close);
153 }
154 }
155}
156
158{
159 return m_fb;
160}
A device containing images (ie. USB stick, CD, storage group etc)
MythVideoDRMBuffer(MythDRMPtr Device, AVDRMFrameDescriptor *DRMDesc, QSize Size)
static DRMHandle Create(MythDRMPtr Device, AVDRMFrameDescriptor *DRMDesc, QSize Size)
uint32_t GetFB() const
#define close
Definition: compat.h:39
static const char * fourcc_str(int i)
Definition: fourcc.h:26
std::shared_ptr< class MythDRMDevice > MythDRMPtr
Definition: mythdrmdevice.h:19
#define DRM_FORMAT_P010
Definition: mythdrmplane.h:25
std::array< uint32_t, 4 > DRMArray
static constexpr uint32_t DRM_FORMAT_NV12
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
#define DRM_FORMAT_R16
#define DRM_FORMAT_R8
#define DRM_FORMAT_GR88
#define DRM_FORMAT_GR1616
#define LOC
static void DebugDRMFrame(AVDRMFrameDescriptor *Desc)
std::shared_ptr< class MythVideoDRMBuffer > DRMHandle
STL namespace.