vdr-plugin-softhddevice-drm-gles 1.6.2
drmbuffer.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: AGPL-3.0-or-later
2
17#include <cstdint>
18#include <fcntl.h>
19#include <sys/mman.h>
20
21extern "C" {
22#include <libavutil/frame.h>
23#include <libavutil/hwcontext_drm.h>
24}
25
26#include <drm_fourcc.h>
27#include <xf86drm.h>
28#include <xf86drmMode.h>
29
30#include "drmbuffer.h"
31#include "logger.h"
32#include "pool.h"
33
39/*****************************************************************************
40 * Drm Buffer
41 ****************************************************************************/
42
49{
50 m_dirty = false;
51 m_dmaBufHandle[0] = 0;
52
53 m_numPlanes = 0;
54 for (int i = 0; i < 4; i++) {
55 m_pPlane[i] = nullptr;
56 }
57}
58
67 : m_width(src->m_width),
68 m_height(src->m_height),
69 m_pixFmt(src->m_pixFmt),
70 m_rectOnScreen(src->GetScreenRect()),
71 m_fbId(src->m_fbId),
72 m_numPlanes(src->m_numPlanes),
73 m_numObjects(src->m_numObjects)
74{
75 m_dirty = false;
76
77 for (int object = 0; object < m_numObjects; object++) {
78 m_dmaBufHandle[object] = src->m_dmaBufHandle[object];
79 }
80
81 for (int i = 0; i < src->m_numPlanes; i++) {
82 m_size[i] = src->m_size[i];
83 m_pitch[i] = src->m_pitch[i];
84 m_planePrimeHandle[i] = src->m_planePrimeHandle[i];
85 m_offset[i] = src->m_offset[i];
86 m_objIdx[i] = src->m_objIdx[i];
87 }
88
89 void *src_buffer = NULL;
90 void *dst_buffer = NULL;
91
92 // planes aren't mmapped, do it (PRIME)
93 if (!src->m_pPlane[0]) {
94 for (int object = 0; object < m_numObjects; object++) {
95 // memcpy mmapped data
96 dst_buffer = malloc(src->m_size[object]);
97 src_buffer = mmap(NULL, src->m_size[object], PROT_READ, MAP_SHARED, src->m_dmaBufHandle[object], 0);
98 if (src_buffer == MAP_FAILED) {
99 LOGERROR("drmbuffer: %s (clone): cannot map buffer size %d prime_fd %d (%d): %m",
100 __FUNCTION__, src->m_size[object], src->m_dmaBufHandle[object], errno);
101 return;
102 }
103
104 LOGDEBUG2(L_GRAB, "drmbuffer: %s (clone): Copy %p to %p", __FUNCTION__, src_buffer, dst_buffer);
105 memcpy(dst_buffer, src_buffer, src->m_size[object]);
106 munmap(src_buffer, src->m_size[object]);
107 for (int plane = 0; plane < m_numPlanes; plane++) {
108 if (m_objIdx[plane] == object) {
110 LOGDEBUG2(L_GRAB, "drmbuffer: %s (clone): plane[%d] gets %p (object %d)", __FUNCTION__, plane, dst_buffer, object);
111 }
112 }
113 }
114 } else {
115 for (int plane = 0; plane < m_numPlanes; plane++) {
117 memcpy(dst_buffer, src->m_pPlane[plane], src->m_size[plane]);
119 }
120 }
121
122 for (int plane = 0; plane < m_numPlanes; plane++) {
123 LOGDEBUG2(L_GRAB, "drmbuffer: %s (clone): Cloned plane %d address %p pitch %d offset %d handle %d size %d",
125 }
126}
127
128#ifdef USE_GLES
141 : m_width(width),
142 m_height(height),
143 m_pixFmt(pixFmt),
144 m_drmDeviceFd(fdDrm),
145 m_pBo(bo)
146{
147 m_numPlanes = 0;
148 for (int i = 0; i < 4; i++) {
149 m_pPlane[i] = nullptr;
151 m_offset[i] = 0;
152 m_pitch[i] = 0;
153 m_size[i] = 0;
154 }
155 m_dirty = false;
156}
157#endif
158
163{
165 LOGDEBUG2(L_DRM, "drmbuffer: %s: destroy FB %d DMA-BUF handle %d", __FUNCTION__, m_fbId, m_dmaBufHandle[0]);
166
167 for (int i = 0; i < m_numPlanes; i++) {
168 if (m_pPlane[i]) {
169 if (munmap(m_pPlane[i], m_size[i]))
170 LOGERROR("drmbuffer: %s: failed unmap FB (%d): %m", __FUNCTION__, errno);
171 }
172 }
173
175 LOGERROR("drmbuffer: %s: cannot rm FB (%d): %m", __FUNCTION__, errno);
176
177 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
178 if (close(m_dmaBufHandle[0]))
179 LOGERROR("drmbuffer: %s: error closing DMA-BUF handle %d (%d): %m", __FUNCTION__, m_dmaBufHandle[0], errno);
180 }
181
182 for (int i = 0; i < m_numPlanes; i++) {
183 if (m_pPlane[i]) {
184 memset(&dreq, 0, sizeof(dreq));
185 dreq.handle = m_planePrimeHandle[i];
186
188 LOGERROR("drmbuffer: %s: cannot destroy dumb buffer (%d): %m", __FUNCTION__, errno);
190
191 }
192
193 m_pPlane[i] = 0;
194 m_size[i] = 0;
195 m_pitch[i] = 0;
196 m_offset[i] = 0;
197 m_objIdx[i] = 0;
198 }
199
200 for (int i = 0; i < m_numObjects; i++) {
202 LOGERROR("drmbuffer: %s: cannot close handle %d FB %d GEM (%d): %m", __FUNCTION__, m_objectPrimeHandle[i], m_fbId, errno);
203 }
204
205 m_width = 0;
206 m_height = 0;
207 m_fbId = 0;
208 m_dirty = false;
209 m_numPlanes = 0;
210 m_destroyAfterUse = false;
211}
212
231static const struct format_info format_info_array[] = {
232 { DRM_FORMAT_NV12, "NV12", 2, { { 8, 1, 1 }, { 16, 2, 2 } }, },
233 { DRM_FORMAT_YUV420, "YU12", 3, { { 8, 1, 1 }, { 8, 2, 2 }, {8, 2, 2 } }, },
234 { DRM_FORMAT_ARGB8888, "AR24", 1, { { 32, 1, 1 } }, },
235};
236
237#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
238
247{
248 for (int i = 0; i < (int)ARRAY_SIZE(format_info_array); i++) {
250 return &format_info_array[i];
251 }
252 return NULL;
253}
254
265{
266 uint64_t modifier[4] = { 0, 0, 0, 0 };
269 m_pitch[0] = m_pitch[1] = m_pitch[2] = m_pitch[3] = 0;
270 m_offset[0] = m_offset[1] = m_offset[2] = m_offset[3] = 0;
272
273 m_width = width;
274 m_height = height;
278
279 if (primedata) {
280 // we have no DRM objects yet, so return
281 if (!primedata->nb_objects)
282 LOGFATAL("drmbuffer: %s: No primedata objects available!", __FUNCTION__);
283
284 AVDRMLayerDescriptor *layer = &primedata->layers[0];
285
286 m_pixFmt = layer->format;
287 m_numPlanes = layer->nb_planes;
288 m_numObjects = primedata->nb_objects;
289
290// LOGDEBUG2(L_DRM, "drmbuffer: %s: PRIMEDATA %d x %d, pix_fmt %4.4s nb_planes %d nb_objects %d", __FUNCTION__,
291// m_width, m_height, (char *)&m_pixFmt, m_numPlanes, m_numObjects);
292
293 // create handles for PrimeFDs
294 for (int object = 0; object < primedata->nb_objects; object++) {
295 if (drmPrimeFDToHandle(drmDeviceFd, primedata->objects[object].fd, &m_objectPrimeHandle[object])) {
296 LOGFATAL("drmbuffer: %s: PRIMEDATA Failed to retrieve the Prime Handle %i size %zu (%d): %m", __FUNCTION__,
297 primedata->objects[object].fd,
298 primedata->objects[object].size, errno);
299 }
300
301 m_dmaBufHandle[object] = primedata->objects[object].fd;
302 m_size[object] = primedata->objects[object].size;
303// LOGDEBUG2(L_DRM, "drmbuffer: %s: PRIMEDATA create handle for PrimeFD (%d|%i): PrimeFD %i ToHandle %i size %zu modifier %" PRIx64 "",
304// __FUNCTION__, object, primedata->nb_objects, primedata->objects[object].fd, m_primehandle[object],
305// primedata->objects[object].size, primedata->objects[object].format_modifier);
306 }
307
308 // fill the planes
309 for (int plane = 0; plane < layer->nb_planes; plane++) {
310 int object = layer->planes[plane].object_index;
312 if (handle) {
314 m_pitch[plane] = layer->planes[plane].pitch;
315 m_offset[plane] = layer->planes[plane].offset;
317 if (primedata->objects[object].format_modifier)
318 modifier[plane] = primedata->objects[object].format_modifier;
319
320 // 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!)",
321 // __FUNCTION__, plane, m_handle[plane], m_objIdx[plane], m_pitch[plane], m_offset[plane], m_size[plane], modifier[plane]);
322 }
323 }
326 } else {
328 if (!format_info)
329 LOGFATAL("drmbuffer: %s: No suitable format found!", __FUNCTION__);
330
332
333 // LOGDEBUG2(L_DRM, "drmbuffer: %s: %d x %d, pix_fmt %4.4s nb_planes %d", __FUNCTION__,
334 // m_width, m_height, (char *)&m_pixFmt, m_numPlanes);
335
336 for (int plane = 0; plane < format_info->num_planes; plane++) {
338
340 creq.height = m_height / plane_info->ysub;
341 creq.width = m_width / plane_info->xsub;
342 creq.bpp = plane_info->bitspp;
343 creq.flags = 0;
344 creq.handle = 0;
345 creq.pitch = 0;
346 creq.size = 0;
347
349 LOGFATAL("drmbuffer: %s: cannot create dumb buffer %dx%d@%d (%d): %m", __FUNCTION__,
350 creq.width, creq.height, creq.bpp, errno);
351
352 m_planePrimeHandle[plane] = creq.handle;
353 m_pitch[plane] = creq.pitch;
354 m_size[plane] = creq.size;
355
356 struct drm_mode_map_dumb mreq;
357 memset(&mreq, 0, sizeof(struct drm_mode_map_dumb));
358 mreq.handle = m_planePrimeHandle[plane];
359
361 LOGFATAL("drmbuffer: %s: cannot prepare dumb buffer for mapping (%d): %m", __FUNCTION__, errno);
362
364
365 if (m_pPlane[plane] == MAP_FAILED)
366 LOGFATAL("drmbuffer: %s: cannot map dumb buffer (%d): %m", __FUNCTION__, errno);
367
369
370 // LOGDEBUG2(L_DRM, "drmbuffer: %s: fill plane %d: prime handle %d pitch %d offset %d size %d address %p", __FUNCTION__,
371 // plane, m_planePrimeHandle[plane], m_pitch[plane], m_offset[plane], m_size[plane], m_pPlane[plane]);
372 }
373 }
374
375 int ret = -1;
377
378 if (ret) {
379 if (mod_flags)
380 LOGERROR("drmbuffer: %s: cannot create modifiers framebuffer (%d): %m", __FUNCTION__, errno);
381
384 }
385
386 if (ret)
387 LOGFATAL("drmbuffer: %s: cannot create framebuffer (%d): %m", __FUNCTION__, errno);
388
389 LOGDEBUG2(L_DRM, "drmbuffer: %s: Added %sFB fb_id %d width %d height %d pix_fmt %4.4s", __FUNCTION__,
390 primedata ? "primedata " : "", m_fbId, m_width, m_height, (char *)&m_pixFmt);
391
392 m_dirty = true;
393}
394
399{
400 for (uint32_t i = 0; i < m_width * m_height; ++i) {
401 m_pPlane[0][i] = 0x10;
402 if (i < m_width * m_height / 2)
403 m_pPlane[1][i] = 0x80;
404 }
405}
406
413{
415 m_presentationPending = false;
416
418 Destroy();
419}
420
421/*****************************************************************************
422 * Drm Buffer Pool
423 ****************************************************************************/
424
429{
430 for (const auto &buf : buffer) {
431 if (buf->IsDirty() && buf->DmaBufHandle() == primeFd)
432 return buf.get();
433 }
434
435 return nullptr;
436}
437
442{
443 int i = 0;
444 for (const auto &buf : buffer) {
445 if (!buf->IsDirty())
446 return buf.get();
447
448 i++;
449 }
450
451 return nullptr;
452}
453
458{
459 for (const auto &buf : buffer) {
460 if (buf->IsDirty() && !buf->IsPresentationPending())
461 return buf.get();
462 }
463
464 return nullptr;
465}
466
474{
475 for (const auto &buf : buffer) {
476 if (buf.get() != exceptBuf && buf->IsDirty()) {
477 av_frame_free(&buf->frame);
478 buf->Destroy();
479 }
480 }
481}
482
DRM Buffer.
Definition drmbuffer.h:47
bool m_dirty
true, if the buffer is dirty (it was written to)
Definition drmbuffer.h:108
bool m_destroyAfterUse
true, if buffer should be destroyed after use
Definition drmbuffer.h:127
int m_objIdx[4]
index of the objects
Definition drmbuffer.h:117
bool m_closeHandleOnDestroy
true, if DMA-BUF handle should be closed on destroy
Definition drmbuffer.h:128
int m_numObjects
number of prime objects in the buffer
Definition drmbuffer.h:116
uint32_t m_fbId
framebuffer id
Definition drmbuffer.h:110
uint32_t m_width
buffer width
Definition drmbuffer.h:102
uint32_t m_offset[4]
array of the plane offset
Definition drmbuffer.h:122
uint32_t m_pitch[4]
array of the plane pitch
Definition drmbuffer.h:123
AVFrame * frame
associated AVFrame
Definition drmbuffer.h:95
uint32_t m_objectPrimeHandle[4]
primedata objects prime handles (count is numObjects, index is objIdx)
Definition drmbuffer.h:118
int m_dmaBufHandle[4]
DMA-BUF file descriptor.
Definition drmbuffer.h:115
uint32_t m_pixFmt
buffer pixel format
Definition drmbuffer.h:104
int m_drmDeviceFd
drm device file descriptor
Definition drmbuffer.h:111
uint32_t m_height
buffer height
Definition drmbuffer.h:103
bool m_presentationPending
true, if buffer presentation is pending
Definition drmbuffer.h:126
uint8_t * m_pPlane[4]
array of the plane data
Definition drmbuffer.h:120
uint32_t m_size[4]
array of the plane size
Definition drmbuffer.h:124
uint32_t m_planePrimeHandle[4]
array of the plane handles
Definition drmbuffer.h:121
int m_numPlanes
number of planes in the buffer
Definition drmbuffer.h:113
std::vector< std::unique_ptr< cDrmBuffer > > buffer
Definition pool.h:27
DRM Buffer Header File.
cDrmBuffer(void)
Create a new drm buffer.
Definition drmbuffer.cpp:48
cDrmBuffer * FindUninitilized(void)
Find a clean drm buffer from the buffer pool.
void Setup(int, uint32_t, uint32_t, uint32_t, AVDRMFrameDescriptor *, bool)
Setup the buffer.
int plane
#define ARRAY_SIZE(arr)
cDrmBuffer * FindByDmaBufHandle(int)
Find a drm buffer from the buffer pool by a given prime handle.
void FillBlack(void)
Color the buffer black.
cDrmBuffer * FindNoPresentationPending(void)
Find a dirty drm buffer from the buffer pool which presentation has finished.
const struct format_info * FindFormat(uint32_t format)
Find infos for the given pixel format.
void DestroyAllExcept(cDrmBuffer *)
Destroy all drm buffers except the given one.
void PresentationFinished(void)
The presentation of this buffer has finished.
void Destroy(void)
Clear and destroy the buffer object and its parameters.
static const struct format_info format_info_array[]
Holds the infos of a pixel format.
#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 LOGFATAL
log to LOG_ERR and abort
Definition logger.h:32
@ L_DRM
drm logs
Definition logger.h:55
@ L_GRAB
grabbing logs
Definition logger.h:64
Logger Header File.
Pool Implementation.
uint32_t format
Definition drmbuffer.h:38
uint8_t num_planes
Definition drmbuffer.h:40
struct format_plane_info planes[4]
Definition drmbuffer.h:41