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