vdr-plugin-softhddevice-drm-gles 1.5.9-20e15de
drmbuffer.cpp
Go to the documentation of this file.
1
25#include <cstdint>
26#include <fcntl.h>
27#include <sys/mman.h>
28
29extern "C" {
30#include <libavutil/frame.h>
31#include <libavutil/hwcontext_drm.h>
32}
33
34#include <drm_fourcc.h>
35#include <xf86drm.h>
36#include <xf86drmMode.h>
37
38#include "drmbuffer.h"
39#include "logger.h"
40#include "pool.h"
41
42/*****************************************************************************
43 * cDrmBuffer class
44 ****************************************************************************/
45
52{
53 m_dirty = false;
54 m_dmaBufHandle[0] = 0;
55
56 m_numPlanes = 0;
57 for (int i = 0; i < 4; i++) {
58 m_pPlane[i] = nullptr;
59 }
60}
61
72 : m_width(src->m_width),
73 m_height(src->m_height),
74 m_pixFmt(src->m_pixFmt),
75 m_rectOnScreen(src->GetScreenRect()),
76 m_fbId(src->m_fbId),
77 m_numPlanes(src->m_numPlanes),
78 m_numObjects(src->m_numObjects)
79{
80 m_dirty = false;
81
82 for (int object = 0; object < m_numObjects; object++) {
83 m_dmaBufHandle[object] = src->m_dmaBufHandle[object];
84 }
85
86 for (int i = 0; i < src->m_numPlanes; i++) {
87 m_size[i] = src->m_size[i];
88 m_pitch[i] = src->m_pitch[i];
90 m_offset[i] = src->m_offset[i];
91 m_objIdx[i] = src->m_objIdx[i];
92 }
93
94 void *src_buffer = NULL;
95 void *dst_buffer = NULL;
96
97 // planes aren't mmapped, do it (PRIME)
98 if (!src->m_pPlane[0]) {
99 for (int object = 0; object < m_numObjects; object++) {
100 // memcpy mmapped data
101 dst_buffer = malloc(src->m_size[object]);
102 src_buffer = mmap(NULL, src->m_size[object], PROT_READ, MAP_SHARED, src->m_dmaBufHandle[object], 0);
103 if (src_buffer == MAP_FAILED) {
104 LOGERROR("drmbuffer: %s (clone): cannot map buffer size %d prime_fd %d (%d): %m",
105 __FUNCTION__, src->m_size[object], src->m_dmaBufHandle[object], errno);
106 return;
107 }
108
109 LOGDEBUG2(L_GRAB, "drmbuffer: %s (clone): Copy %p to %p", __FUNCTION__, src_buffer, dst_buffer);
110 memcpy(dst_buffer, src_buffer, src->m_size[object]);
111 munmap(src_buffer, src->m_size[object]);
112 for (int plane = 0; plane < m_numPlanes; plane++) {
113 if (m_objIdx[plane] == object) {
114 m_pPlane[plane] = (uint8_t *)dst_buffer;
115 LOGDEBUG2(L_GRAB, "drmbuffer: %s (clone): plane[%d] gets %p (object %d)", __FUNCTION__, plane, dst_buffer, object);
116 }
117 }
118 }
119 } else {
120 for (int plane = 0; plane < m_numPlanes; plane++) {
121 dst_buffer = malloc(m_size[plane]);
122 memcpy(dst_buffer, src->m_pPlane[plane], src->m_size[plane]);
123 m_pPlane[plane] = (uint8_t *)dst_buffer;
124 }
125 }
126
127 for (int plane = 0; plane < m_numPlanes; plane++) {
128 LOGDEBUG2(L_GRAB, "drmbuffer: %s (clone): Cloned plane %d address %p pitch %d offset %d handle %d size %d",
129 __FUNCTION__, plane, m_pPlane[plane], m_pitch[plane], m_offset[plane], m_planePrimeHandle[plane], m_size[plane]);
130 }
131}
132
133#ifdef USE_GLES
147cDrmBuffer::cDrmBuffer(int fdDrm, uint32_t width, uint32_t height, uint32_t pixFmt, struct gbm_bo *bo)
148 : m_width(width),
149 m_height(height),
150 m_pixFmt(pixFmt),
151 m_drmDeviceFd(fdDrm),
152 m_pBo(bo)
153{
154 m_numPlanes = 0;
155 for (int i = 0; i < 4; i++) {
156 m_pPlane[i] = nullptr;
157 m_planePrimeHandle[i] = 0;
158 m_offset[i] = 0;
159 m_pitch[i] = 0;
160 m_size[i] = 0;
161 }
162 m_dirty = false;
163}
164#endif
165
170{
171 struct drm_mode_destroy_dumb dreq;
172 LOGDEBUG2(L_DRM, "drmbuffer: %s: destroy FB %d DMA-BUF handle %d", __FUNCTION__, m_fbId, m_dmaBufHandle[0]);
173
174 for (int i = 0; i < m_numPlanes; i++) {
175 if (m_pPlane[i]) {
176 if (munmap(m_pPlane[i], m_size[i]))
177 LOGERROR("drmbuffer: %s: failed unmap FB (%d): %m", __FUNCTION__, errno);
178 }
179 }
180
181 if (drmModeRmFB(m_drmDeviceFd, m_fbId) < 0)
182 LOGERROR("drmbuffer: %s: cannot rm FB (%d): %m", __FUNCTION__, errno);
183
184 if (m_closeHandleOnDestroy &&m_dmaBufHandle[0] && fcntl(m_dmaBufHandle[0], F_GETFD) != -1) { // the handle can be invalid in reverse trickspeed, because the decoder is rapidly reopened
185 if (close(m_dmaBufHandle[0]))
186 LOGERROR("drmbuffer: %s: error closing DMA-BUF handle %d (%d): %m", __FUNCTION__, m_dmaBufHandle[0], errno);
187 }
188
189 for (int i = 0; i < m_numPlanes; i++) {
190 if (m_pPlane[i]) {
191 memset(&dreq, 0, sizeof(dreq));
192 dreq.handle = m_planePrimeHandle[i];
193
194 if (drmIoctl(m_drmDeviceFd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq) < 0)
195 LOGERROR("drmbuffer: %s: cannot destroy dumb buffer (%d): %m", __FUNCTION__, errno);
196 m_planePrimeHandle[i] = 0;
197
198 }
199
200 m_pPlane[i] = 0;
201 m_size[i] = 0;
202 m_pitch[i] = 0;
203 m_offset[i] = 0;
204 m_objIdx[i] = 0;
205 }
206
207 for (int i = 0; i < m_numObjects; i++) {
208 if (m_objectPrimeHandle[i]) {
209 // this can happen, when we SetPlayMode 0 while in trickspeed
210 // does not show negative effects, but its not nice though -> TODO
211 if (drmIoctl(m_drmDeviceFd, DRM_IOCTL_GEM_CLOSE, &m_objectPrimeHandle[i]) < 0)
212 LOGERROR("drmbuffer: %s: cannot close handle %d FB %d GEM (%d): %m", __FUNCTION__, m_objectPrimeHandle[i], m_fbId, errno);
213 }
214 }
215
216 m_width = 0;
217 m_height = 0;
218 m_fbId = 0;
219 m_dirty = false;
220 m_numPlanes = 0;
221 m_destroyAfterUse = false;
222}
223
242static const struct format_info format_info_array[] = {
243 { DRM_FORMAT_NV12, "NV12", 2, { { 8, 1, 1 }, { 16, 2, 2 } }, },
244 { DRM_FORMAT_YUV420, "YU12", 3, { { 8, 1, 1 }, { 8, 2, 2 }, {8, 2, 2 } }, },
245 { DRM_FORMAT_ARGB8888, "AR24", 1, { { 32, 1, 1 } }, },
246};
247
248#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
249
257const struct format_info *FindFormat(uint32_t format)
258{
259 for (int i = 0; i < (int)ARRAY_SIZE(format_info_array); i++) {
261 return &format_info_array[i];
262 }
263 return NULL;
264}
265
275void cDrmBuffer::Setup(int drmDeviceFd, uint32_t width, uint32_t height, uint32_t pixFmt, AVDRMFrameDescriptor *primedata, bool closeHandleOnDestroy)
276{
277 uint64_t modifier[4] = { 0, 0, 0, 0 };
278 uint32_t mod_flags = 0;
280 m_pitch[0] = m_pitch[1] = m_pitch[2] = m_pitch[3] = 0;
281 m_offset[0] = m_offset[1] = m_offset[2] = m_offset[3] = 0;
283
284 m_width = width;
285 m_height = height;
286 m_pixFmt = pixFmt;
287 m_drmDeviceFd = drmDeviceFd;
288 m_closeHandleOnDestroy = closeHandleOnDestroy;
289
290 if (primedata) {
291 // we have no DRM objects yet, so return
292 if (!primedata->nb_objects)
293 LOGFATAL("drmbuffer: %s: No primedata objects available!", __FUNCTION__);
294
295 AVDRMLayerDescriptor *layer = &primedata->layers[0];
296
297 m_pixFmt = layer->format;
298 m_numPlanes = layer->nb_planes;
299 m_numObjects = primedata->nb_objects;
300
301// LOGDEBUG2(L_DRM, "drmbuffer: %s: PRIMEDATA %d x %d, pix_fmt %4.4s nb_planes %d nb_objects %d", __FUNCTION__,
302// m_width, m_height, (char *)&m_pixFmt, m_numPlanes, m_numObjects);
303
304 // create handles for PrimeFDs
305 for (int object = 0; object < primedata->nb_objects; object++) {
306 if (drmPrimeFDToHandle(drmDeviceFd, primedata->objects[object].fd, &m_objectPrimeHandle[object])) {
307 LOGFATAL("drmbuffer: %s: PRIMEDATA Failed to retrieve the Prime Handle %i size %zu (%d): %m", __FUNCTION__,
308 primedata->objects[object].fd,
309 primedata->objects[object].size, errno);
310 }
311
312 m_dmaBufHandle[object] = primedata->objects[object].fd;
313 m_size[object] = primedata->objects[object].size;
314// LOGDEBUG2(L_DRM, "drmbuffer: %s: PRIMEDATA create handle for PrimeFD (%d|%i): PrimeFD %i ToHandle %i size %zu modifier %" PRIx64 "",
315// __FUNCTION__, object, primedata->nb_objects, primedata->objects[object].fd, m_primehandle[object],
316// primedata->objects[object].size, primedata->objects[object].format_modifier);
317 }
318
319 // fill the planes
320 for (int plane = 0; plane < layer->nb_planes; plane++) {
321 int object = layer->planes[plane].object_index;
322 uint32_t handle = m_objectPrimeHandle[object];
323 if (handle) {
324 m_planePrimeHandle[plane] = handle;
325 m_pitch[plane] = layer->planes[plane].pitch;
326 m_offset[plane] = layer->planes[plane].offset;
327 m_objIdx[plane] = object;
328 if (primedata->objects[object].format_modifier)
329 modifier[plane] = primedata->objects[object].format_modifier;
330
331 // LOGDEBUG2(L_DRM, "drmbuffer: %s: PRIMEDATA fill plane %d: handle %d object_index %i pitch %d offset %d size %d modifier %" PRIx64 " (plane not mapped!)",
332 // __FUNCTION__, plane, m_handle[plane], m_objIdx[plane], m_pitch[plane], m_offset[plane], m_size[plane], modifier[plane]);
333 }
334 }
335 if (modifier[0] && modifier[0] != DRM_FORMAT_MOD_INVALID)
336 mod_flags = DRM_MODE_FB_MODIFIERS;
337 } else {
339 if (!format_info)
340 LOGFATAL("drmbuffer: %s: No suitable format found!", __FUNCTION__);
341
343
344 // LOGDEBUG2(L_DRM, "drmbuffer: %s: %d x %d, pix_fmt %4.4s nb_planes %d", __FUNCTION__,
345 // m_width, m_height, (char *)&m_pixFmt, m_numPlanes);
346
347 for (int plane = 0; plane < format_info->num_planes; plane++) {
348 const struct format_plane_info *plane_info = &format_info->planes[plane];
349
350 struct drm_mode_create_dumb creq;
351 creq.height = m_height / plane_info->ysub;
352 creq.width = m_width / plane_info->xsub;
353 creq.bpp = plane_info->bitspp;
354 creq.flags = 0;
355 creq.handle = 0;
356 creq.pitch = 0;
357 creq.size = 0;
358
359 if (drmIoctl(drmDeviceFd, DRM_IOCTL_MODE_CREATE_DUMB, &creq) < 0)
360 LOGFATAL("drmbuffer: %s: cannot create dumb buffer %dx%d@%d (%d): %m", __FUNCTION__,
361 creq.width, creq.height, creq.bpp, errno);
362
363 m_planePrimeHandle[plane] = creq.handle;
364 m_pitch[plane] = creq.pitch;
365 m_size[plane] = creq.size;
366
367 struct drm_mode_map_dumb mreq;
368 memset(&mreq, 0, sizeof(struct drm_mode_map_dumb));
369 mreq.handle = m_planePrimeHandle[plane];
370
371 if (drmIoctl(drmDeviceFd, DRM_IOCTL_MODE_MAP_DUMB, &mreq))
372 LOGFATAL("drmbuffer: %s: cannot prepare dumb buffer for mapping (%d): %m", __FUNCTION__, errno);
373
374 m_pPlane[plane] = (uint8_t *)mmap(0, creq.size, PROT_READ | PROT_WRITE, MAP_SHARED, drmDeviceFd, mreq.offset);
375
376 if (m_pPlane[plane] == MAP_FAILED)
377 LOGFATAL("drmbuffer: %s: cannot map dumb buffer (%d): %m", __FUNCTION__, errno);
378
379 memset(m_pPlane[plane], 0, m_size[plane]);
380
381 // LOGDEBUG2(L_DRM, "drmbuffer: %s: fill plane %d: prime handle %d pitch %d offset %d size %d address %p", __FUNCTION__,
382 // plane, m_planePrimeHandle[plane], m_pitch[plane], m_offset[plane], m_size[plane], m_pPlane[plane]);
383 }
384 }
385
386 int ret = -1;
387 ret = drmModeAddFB2WithModifiers(drmDeviceFd, m_width, m_height, m_pixFmt, m_planePrimeHandle, m_pitch, m_offset, modifier, &m_fbId, mod_flags);
388
389 if (ret) {
390 if (mod_flags)
391 LOGERROR("drmbuffer: %s: cannot create modifiers framebuffer (%d): %m", __FUNCTION__, errno);
392
393 ret = drmModeAddFB2(drmDeviceFd, m_width, m_height, m_pixFmt,
395 }
396
397 if (ret)
398 LOGFATAL("drmbuffer: %s: cannot create framebuffer (%d): %m", __FUNCTION__, errno);
399
400 LOGDEBUG2(L_DRM, "drmbuffer: %s: Added %sFB fb_id %d width %d height %d pix_fmt %4.4s", __FUNCTION__,
401 primedata ? "primedata " : "", m_fbId, m_width, m_height, (char *)&m_pixFmt);
402
403 m_dirty = true;
404}
405
410{
411 for (uint32_t i = 0; i < m_width * m_height; ++i) {
412 m_pPlane[0][i] = 0x10;
413 if (i < m_width * m_height / 2)
414 m_pPlane[1][i] = 0x80;
415 }
416}
417
419{
420 for (const auto &buf : buffer) {
421 if (buf->IsDirty() && buf->DmaBufHandle() == primeFd)
422 return buf.get();
423 }
424
425 return nullptr;
426}
427
429{
430 int i = 0;
431 for (const auto &buf : buffer) {
432 if (!buf->IsDirty())
433 return buf.get();
434
435 i++;
436 }
437
438 return nullptr;
439}
440
442{
443 for (const auto &buf : buffer) {
444 if (buf->IsDirty() && !buf->IsPresentationPending())
445 return buf.get();
446 }
447
448 return nullptr;
449}
450
452{
453 for (const auto &buf : buffer) {
454 if (buf.get() != exceptBuf && buf->IsDirty()) {
455 av_frame_free(&buf->frame);
456 buf->Destroy();
457 }
458 }
459}
460
462{
463 av_frame_free(&frame);
464 m_presentationPending = false;
465
467 Destroy();
468}
cDrmBuffer * FindUninitilized(void)
cDrmBuffer * FindByDmaBufHandle(int)
cDrmBuffer * FindNoPresentationPending(void)
void DestroyAllExcept(cDrmBuffer *)
bool m_dirty
true, if the buffer is dirty (it was written to)
Definition drmbuffer.h:112
cDrmBuffer(void)
cDrmBuffer constructor
Definition drmbuffer.cpp:51
bool m_destroyAfterUse
true, if buffer should be destroyed after use
Definition drmbuffer.h:131
int m_objIdx[4]
index of the objects
Definition drmbuffer.h:121
bool m_closeHandleOnDestroy
true, if DMA-BUF handle should be closed on destroy
Definition drmbuffer.h:132
void Setup(int, uint32_t, uint32_t, uint32_t, AVDRMFrameDescriptor *, bool)
Setup the buffer.
int m_numObjects
number of prime objects in the buffer
Definition drmbuffer.h:120
uint32_t m_fbId
framebuffer id
Definition drmbuffer.h:114
uint32_t m_width
buffer width
Definition drmbuffer.h:106
uint32_t m_offset[4]
array of the plane offset
Definition drmbuffer.h:126
uint32_t m_pitch[4]
array of the plane pitch
Definition drmbuffer.h:127
void FillBlack(void)
Color the buffer black.
AVFrame * frame
associated AVFrame
Definition drmbuffer.h:99
uint32_t m_objectPrimeHandle[4]
primedata objects prime handles (count is numObjects, index is objIdx)
Definition drmbuffer.h:122
int m_dmaBufHandle[4]
DMA-BUF file descriptor.
Definition drmbuffer.h:119
uint32_t m_pixFmt
buffer pixel format
Definition drmbuffer.h:108
int m_drmDeviceFd
drm device file descriptor
Definition drmbuffer.h:115
bool IsDirty(void)
Definition drmbuffer.h:71
uint32_t m_height
buffer height
Definition drmbuffer.h:107
void PresentationFinished(void)
bool m_presentationPending
true, if buffer is pending presentation
Definition drmbuffer.h:130
uint8_t * m_pPlane[4]
array of the plane data
Definition drmbuffer.h:124
void Destroy(void)
Clear and destroy the buffer object and its parameters.
uint32_t m_size[4]
array of the plane size
Definition drmbuffer.h:128
uint32_t m_planePrimeHandle[4]
array of the plane handles
Definition drmbuffer.h:125
int m_numPlanes
number of planes in the buffer
Definition drmbuffer.h:117
std::vector< std::unique_ptr< cDrmBuffer > > buffer
Definition pool.h:27
#define ARRAY_SIZE(arr)
const struct format_info * FindFormat(uint32_t format)
Find infos for the given pixel format.
static const struct format_info format_info_array[]
Infos of a pixel format.
DRM buffer header file.
Logger class header file.
#define LOGDEBUG2
Definition logger.h:45
#define LOGERROR
Definition logger.h:41
#define L_DRM
Definition logger.h:57
#define L_GRAB
Definition logger.h:66
#define LOGFATAL
Logger macros.
Definition logger.h:40
Pool class header file.
uint32_t format
Definition drmbuffer.h:45
uint8_t num_planes
Definition drmbuffer.h:47
struct format_plane_info planes[4]
Definition drmbuffer.h:48