vdr-plugin-softhddevice-drm-gles 1.6.4-d0291bb
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
34/*****************************************************************************
35 * Drm Buffer
36 ****************************************************************************/
37
44{
45 m_dirty = false;
46 m_dmaBufHandle[0] = 0;
47
48 m_numPlanes = 0;
49 for (int i = 0; i < 4; i++) {
50 m_pPlane[i] = nullptr;
51 }
52}
53
62 : m_width(src->m_width),
63 m_height(src->m_height),
64 m_pixFmt(src->m_pixFmt),
65 m_rectOnScreen(src->GetScreenRect()),
66 m_fbId(src->m_fbId),
67 m_numPlanes(src->m_numPlanes),
68 m_numObjects(src->m_numObjects)
69{
70 m_dirty = false;
71
72 for (int object = 0; object < m_numObjects; object++) {
73 m_dmaBufHandle[object] = src->m_dmaBufHandle[object];
74 }
75
76 for (int i = 0; i < src->m_numPlanes; i++) {
77 m_size[i] = src->m_size[i];
78 m_pitch[i] = src->m_pitch[i];
79 m_planePrimeHandle[i] = src->m_planePrimeHandle[i];
80 m_offset[i] = src->m_offset[i];
81 m_objIdx[i] = src->m_objIdx[i];
82 }
83
84 void *src_buffer = NULL;
85 void *dst_buffer = NULL;
86
87 // planes aren't mmapped, do it (PRIME)
88 if (!src->m_pPlane[0]) {
89 for (int object = 0; object < m_numObjects; object++) {
90 // memcpy mmapped data
91 dst_buffer = malloc(src->m_size[object]);
92 src_buffer = mmap(NULL, src->m_size[object], PROT_READ, MAP_SHARED, src->m_dmaBufHandle[object], 0);
93 if (src_buffer == MAP_FAILED) {
94 LOGERROR("drmbuffer: %s (clone): cannot map buffer size %d prime_fd %d (%d): %m",
95 __FUNCTION__, src->m_size[object], src->m_dmaBufHandle[object], errno);
96 return;
97 }
98
99 LOGDEBUG2(L_GRAB, "drmbuffer: %s (clone): Copy %p to %p", __FUNCTION__, src_buffer, dst_buffer);
100 memcpy(dst_buffer, src_buffer, src->m_size[object]);
101 munmap(src_buffer, src->m_size[object]);
102 for (int plane = 0; plane < m_numPlanes; plane++) {
103 if (m_objIdx[plane] == object) {
105 LOGDEBUG2(L_GRAB, "drmbuffer: %s (clone): plane[%d] gets %p (object %d)", __FUNCTION__, plane, dst_buffer, object);
106 }
107 }
108 }
109 } else {
110 for (int plane = 0; plane < m_numPlanes; plane++) {
112 memcpy(dst_buffer, src->m_pPlane[plane], src->m_size[plane]);
114 }
115 }
116
117 for (int plane = 0; plane < m_numPlanes; plane++) {
118 LOGDEBUG2(L_GRAB, "drmbuffer: %s (clone): Cloned plane %d address %p pitch %d offset %d handle %d size %d",
120 }
121}
122
123#ifdef USE_GLES
136 : m_width(width),
137 m_height(height),
138 m_pixFmt(pixFmt),
139 m_drmDeviceFd(fdDrm),
140 m_pBo(bo)
141{
142 m_numPlanes = 0;
143 for (int i = 0; i < 4; i++) {
144 m_pPlane[i] = nullptr;
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{
160 LOGDEBUG2(L_DRM, "drmbuffer: %s: destroy FB %d DMA-BUF handle %d", __FUNCTION__, m_fbId, m_dmaBufHandle[0]);
161
162 for (int i = 0; i < m_numPlanes; i++) {
163 if (m_pPlane[i]) {
164 if (munmap(m_pPlane[i], m_size[i]))
165 LOGERROR("drmbuffer: %s: failed unmap FB (%d): %m", __FUNCTION__, errno);
166 }
167 }
168
170 LOGERROR("drmbuffer: %s: cannot rm FB (%d): %m", __FUNCTION__, errno);
171
172 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
173 if (close(m_dmaBufHandle[0]))
174 LOGERROR("drmbuffer: %s: error closing DMA-BUF handle %d (%d): %m", __FUNCTION__, m_dmaBufHandle[0], errno);
175 }
176
177 for (int i = 0; i < m_numPlanes; i++) {
178 if (m_pPlane[i]) {
179 memset(&dreq, 0, sizeof(dreq));
180 dreq.handle = m_planePrimeHandle[i];
181
183 LOGERROR("drmbuffer: %s: cannot destroy dumb buffer (%d): %m", __FUNCTION__, errno);
185
186 }
187
188 m_pPlane[i] = 0;
189 m_size[i] = 0;
190 m_pitch[i] = 0;
191 m_offset[i] = 0;
192 m_objIdx[i] = 0;
193 }
194
195 for (int i = 0; i < m_numObjects; i++) {
197 LOGERROR("drmbuffer: %s: cannot close handle %d FB %d GEM (%d): %m", __FUNCTION__, m_objectPrimeHandle[i], m_fbId, errno);
198 }
199
200 m_width = 0;
201 m_height = 0;
202 m_fbId = 0;
203 m_dirty = false;
204 m_numPlanes = 0;
205 m_destroyAfterUse = false;
206}
207
226static const struct format_info format_info_array[] = {
227 { DRM_FORMAT_NV12, "NV12", 2, { { 8, 1, 1 }, { 16, 2, 2 } }, },
228 { DRM_FORMAT_YUV420, "YU12", 3, { { 8, 1, 1 }, { 8, 2, 2 }, {8, 2, 2 } }, },
229 { DRM_FORMAT_ARGB8888, "AR24", 1, { { 32, 1, 1 } }, },
230};
231
232#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
233
242{
243 for (int i = 0; i < (int)ARRAY_SIZE(format_info_array); i++) {
245 return &format_info_array[i];
246 }
247 return NULL;
248}
249
260{
261 uint64_t modifier[4] = { 0, 0, 0, 0 };
264 m_pitch[0] = m_pitch[1] = m_pitch[2] = m_pitch[3] = 0;
265 m_offset[0] = m_offset[1] = m_offset[2] = m_offset[3] = 0;
267
268 m_width = width;
269 m_height = height;
273
274 if (primedata) {
275 // we have no DRM objects yet, so return
276 if (!primedata->nb_objects)
277 LOGFATAL("drmbuffer: %s: No primedata objects available!", __FUNCTION__);
278
279 AVDRMLayerDescriptor *layer = &primedata->layers[0];
280
281 m_pixFmt = layer->format;
282 m_numPlanes = layer->nb_planes;
283 m_numObjects = primedata->nb_objects;
284
285// LOGDEBUG2(L_DRM, "drmbuffer: %s: PRIMEDATA %d x %d, pix_fmt %4.4s nb_planes %d nb_objects %d", __FUNCTION__,
286// m_width, m_height, (char *)&m_pixFmt, m_numPlanes, m_numObjects);
287
288 // create handles for PrimeFDs
289 for (int object = 0; object < primedata->nb_objects; object++) {
290 if (drmPrimeFDToHandle(drmDeviceFd, primedata->objects[object].fd, &m_objectPrimeHandle[object])) {
291 LOGFATAL("drmbuffer: %s: PRIMEDATA Failed to retrieve the Prime Handle %i size %zu (%d): %m", __FUNCTION__,
292 primedata->objects[object].fd,
293 primedata->objects[object].size, errno);
294 }
295
296 m_dmaBufHandle[object] = primedata->objects[object].fd;
297 m_size[object] = primedata->objects[object].size;
298// LOGDEBUG2(L_DRM, "drmbuffer: %s: PRIMEDATA create handle for PrimeFD (%d|%i): PrimeFD %i ToHandle %i size %zu modifier %" PRIx64 "",
299// __FUNCTION__, object, primedata->nb_objects, primedata->objects[object].fd, m_primehandle[object],
300// primedata->objects[object].size, primedata->objects[object].format_modifier);
301 }
302
303 // fill the planes
304 for (int plane = 0; plane < layer->nb_planes; plane++) {
305 int object = layer->planes[plane].object_index;
307 if (handle) {
309 m_pitch[plane] = layer->planes[plane].pitch;
310 m_offset[plane] = layer->planes[plane].offset;
312 if (primedata->objects[object].format_modifier)
313 modifier[plane] = primedata->objects[object].format_modifier;
314
315 // 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!)",
316 // __FUNCTION__, plane, m_handle[plane], m_objIdx[plane], m_pitch[plane], m_offset[plane], m_size[plane], modifier[plane]);
317 }
318 }
321 } else {
323 if (!format_info)
324 LOGFATAL("drmbuffer: %s: No suitable format found!", __FUNCTION__);
325
327
328 // LOGDEBUG2(L_DRM, "drmbuffer: %s: %d x %d, pix_fmt %4.4s nb_planes %d", __FUNCTION__,
329 // m_width, m_height, (char *)&m_pixFmt, m_numPlanes);
330
331 for (int plane = 0; plane < format_info->num_planes; plane++) {
333
335 creq.height = m_height / plane_info->ysub;
336 creq.width = m_width / plane_info->xsub;
337 creq.bpp = plane_info->bitspp;
338 creq.flags = 0;
339 creq.handle = 0;
340 creq.pitch = 0;
341 creq.size = 0;
342
344 LOGFATAL("drmbuffer: %s: cannot create dumb buffer %dx%d@%d (%d): %m", __FUNCTION__,
345 creq.width, creq.height, creq.bpp, errno);
346
347 m_planePrimeHandle[plane] = creq.handle;
348 m_pitch[plane] = creq.pitch;
349 m_size[plane] = creq.size;
350
351 struct drm_mode_map_dumb mreq;
352 memset(&mreq, 0, sizeof(struct drm_mode_map_dumb));
353 mreq.handle = m_planePrimeHandle[plane];
354
356 LOGFATAL("drmbuffer: %s: cannot prepare dumb buffer for mapping (%d): %m", __FUNCTION__, errno);
357
359
360 if (m_pPlane[plane] == MAP_FAILED)
361 LOGFATAL("drmbuffer: %s: cannot map dumb buffer (%d): %m", __FUNCTION__, errno);
362
364
365 // LOGDEBUG2(L_DRM, "drmbuffer: %s: fill plane %d: prime handle %d pitch %d offset %d size %d address %p", __FUNCTION__,
366 // plane, m_planePrimeHandle[plane], m_pitch[plane], m_offset[plane], m_size[plane], m_pPlane[plane]);
367 }
368 }
369
370 int ret = -1;
372
373 if (ret) {
374 if (mod_flags)
375 LOGERROR("drmbuffer: %s: cannot create modifiers framebuffer (%d): %m", __FUNCTION__, errno);
376
379 }
380
381 if (ret)
382 LOGFATAL("drmbuffer: %s: cannot create framebuffer (%d): %m", __FUNCTION__, errno);
383
384 LOGDEBUG2(L_DRM, "drmbuffer: %s: Added %sFB fb_id %d width %d height %d pix_fmt %4.4s", __FUNCTION__,
385 primedata ? "primedata " : "", m_fbId, m_width, m_height, (char *)&m_pixFmt);
386
387 m_dirty = true;
388}
389
394{
395 for (uint32_t i = 0; i < m_width * m_height; ++i) {
396 m_pPlane[0][i] = 0x10;
397 if (i < m_width * m_height / 2)
398 m_pPlane[1][i] = 0x80;
399 }
400}
401
408{
410 m_presentationPending = false;
411
413 Destroy();
414}
415
416/*****************************************************************************
417 * Drm Buffer Pool
418 ****************************************************************************/
419
424{
425 for (const auto &buf : buffer) {
426 if (buf->IsDirty() && buf->DmaBufHandle() == primeFd)
427 return buf.get();
428 }
429
430 return nullptr;
431}
432
437{
438 int i = 0;
439 for (const auto &buf : buffer) {
440 if (!buf->IsDirty())
441 return buf.get();
442
443 i++;
444 }
445
446 return nullptr;
447}
448
453{
454 for (const auto &buf : buffer) {
455 if (buf->IsDirty() && !buf->IsPresentationPending())
456 return buf.get();
457 }
458
459 return nullptr;
460}
461
469{
470 for (const auto &buf : buffer) {
471 if (buf.get() != exceptBuf && buf->IsDirty()) {
472 av_frame_free(&buf->frame);
473 buf->Destroy();
474 }
475 }
476}
cDrmBuffer * FindUninitilized(void)
Find a clean drm buffer from the buffer pool.
cDrmBuffer * FindByDmaBufHandle(int)
Find a drm buffer from the buffer pool by a given prime handle.
cDrmBuffer * FindNoPresentationPending(void)
Find a dirty drm buffer from the buffer pool which presentation has finished.
void DestroyAllExcept(cDrmBuffer *)
Destroy all drm buffers except the given one.
DRM Buffer.
Definition drmbuffer.h:46
bool m_dirty
true, if the buffer is dirty (it was written to)
Definition drmbuffer.h:107
cDrmBuffer(void)
Create a new drm buffer.
Definition drmbuffer.cpp:43
bool m_destroyAfterUse
true, if buffer should be destroyed after use
Definition drmbuffer.h:126
int m_objIdx[4]
index of the objects
Definition drmbuffer.h:116
bool m_closeHandleOnDestroy
true, if DMA-BUF handle should be closed on destroy
Definition drmbuffer.h:127
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:115
uint32_t m_fbId
framebuffer id
Definition drmbuffer.h:109
uint32_t m_width
buffer width
Definition drmbuffer.h:101
uint32_t m_offset[4]
array of the plane offset
Definition drmbuffer.h:121
uint32_t m_pitch[4]
array of the plane pitch
Definition drmbuffer.h:122
void FillBlack(void)
Color the buffer black.
AVFrame * frame
associated AVFrame
Definition drmbuffer.h:94
uint32_t m_objectPrimeHandle[4]
primedata objects prime handles (count is numObjects, index is objIdx)
Definition drmbuffer.h:117
int m_dmaBufHandle[4]
DMA-BUF file descriptor.
Definition drmbuffer.h:114
uint32_t m_pixFmt
buffer pixel format
Definition drmbuffer.h:103
int m_drmDeviceFd
drm device file descriptor
Definition drmbuffer.h:110
uint32_t m_height
buffer height
Definition drmbuffer.h:102
void PresentationFinished(void)
The presentation of this buffer has finished.
bool m_presentationPending
true, if buffer presentation is pending
Definition drmbuffer.h:125
uint8_t * m_pPlane[4]
array of the plane data
Definition drmbuffer.h:119
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:123
uint32_t m_planePrimeHandle[4]
array of the plane handles
Definition drmbuffer.h:120
int m_numPlanes
number of planes in the buffer
Definition drmbuffer.h:112
std::vector< std::unique_ptr< cDrmBuffer > > buffer
Definition pool.h:24
#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[]
Holds the infos of a pixel format.
DRM Buffer Header File.
int plane
#define LOGDEBUG2
log to LOG_DEBUG and add a prefix
Definition logger.h:47
#define LOGERROR
log to LOG_ERR
Definition logger.h:39
#define LOGFATAL
log to LOG_ERR and abort
Definition logger.h:37
@ L_DRM
drm logs
Definition logger.h:60
@ L_GRAB
grabbing logs
Definition logger.h:69
Logger Header File.
Pool Implementation.
uint32_t format
Definition drmbuffer.h:35
uint8_t num_planes
Definition drmbuffer.h:37
struct format_plane_info planes[4]
Definition drmbuffer.h:38