vdr-plugin-softhddevice-drm-gles 1.7.3-98a2ef7
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
54#ifdef USE_GLES
67 : m_width(width),
68 m_height(height),
69 m_pixFmt(pixFmt),
70 m_drmDeviceFd(fdDrm),
71 m_pBo(bo)
72{
73 m_numPlanes = 0;
75
76 for (int i = 0; i < 4; i++) {
77 m_pPlane[i] = nullptr;
79 m_offset[i] = 0;
80 m_pitch[i] = 0;
81 m_size[i] = 0;
82 }
83 m_dirty = false;
84}
85#endif
86
91{
93 LOGDEBUG2(L_DRM, "drmbuffer: %s: destroy FB %d DMA-BUF handle %d", __FUNCTION__, m_fbId, m_dmaBufHandle[0]);
94
95 for (int i = 0; i < m_numPlanes; i++) {
96 if (m_pPlane[i] && m_size[i]) {
97 if (munmap(m_pPlane[i], m_size[i]))
98 LOGERROR("drmbuffer: %s: failed unmap FB (%d): %m", __FUNCTION__, errno);
99 }
100 }
101
103 LOGERROR("drmbuffer: %s: cannot rm FB (%d): %m", __FUNCTION__, errno);
104
105 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
106 if (close(m_dmaBufHandle[0]))
107 LOGERROR("drmbuffer: %s: error closing DMA-BUF handle %d (%d): %m", __FUNCTION__, m_dmaBufHandle[0], errno);
108 }
109
110 for (int i = 0; i < m_numPlanes; i++) {
111 if (m_pPlane[i] && m_size[i]) {
112 memset(&dreq, 0, sizeof(dreq));
113 dreq.handle = m_planePrimeHandle[i];
114
116 LOGERROR("drmbuffer: %s: cannot destroy dumb buffer (%d): %m", __FUNCTION__, errno);
118
119 }
120
121 m_pPlane[i] = 0;
122 m_size[i] = 0;
123 m_pitch[i] = 0;
124 m_offset[i] = 0;
125 m_objIdx[i] = 0;
126 }
127
128 for (int i = 0; i < m_numObjects; i++) {
130 LOGERROR("drmbuffer: %s: cannot close handle %d FB %d GEM (%d): %m", __FUNCTION__, m_objectPrimeHandle[i], m_fbId, errno);
131 }
132
133 m_width = 0;
134 m_height = 0;
135 m_fbId = 0;
136 m_dirty = false;
137 m_numPlanes = 0;
138 m_destroyAfterUse = false;
140}
141
156{
157 uint64_t modifier[4] = { 0, 0, 0, 0 };
160 m_pitch[0] = m_pitch[1] = m_pitch[2] = m_pitch[3] = 0;
161 m_offset[0] = m_offset[1] = m_offset[2] = m_offset[3] = 0;
163
164 m_width = width;
165 m_height = height;
169
170 if (primedata) {
171 // we have no DRM objects yet, so return
172 if (!primedata->nb_objects)
173 LOGFATAL("drmbuffer: %s: No primedata objects available!", __FUNCTION__);
174
175 AVDRMLayerDescriptor *layer = &primedata->layers[0];
176
177 m_pixFmt = layer->format;
178 m_numPlanes = layer->nb_planes;
179 m_numObjects = primedata->nb_objects;
180
181 //LOGDEBUG2(L_DRM, "drmbuffer: %s: PRIMEDATA %d x %d, pix_fmt %4.4s nb_planes %d nb_objects %d", __FUNCTION__,
182 // m_width, m_height, (char *)&m_pixFmt, m_numPlanes, m_numObjects);
183
184 // create handles for PrimeFDs
185 for (int object = 0; object < primedata->nb_objects; object++) {
186 if (drmPrimeFDToHandle(drmDeviceFd, primedata->objects[object].fd, &m_objectPrimeHandle[object])) {
187 LOGFATAL("drmbuffer: %s: PRIMEDATA Failed to retrieve the Prime Handle %i size %zu (%d): %m", __FUNCTION__,
188 primedata->objects[object].fd,
189 primedata->objects[object].size, errno);
190 }
191
192 m_dmaBufHandle[object] = primedata->objects[object].fd;
193 m_size[object] = primedata->objects[object].size;
194 //LOGDEBUG2(L_DRM, "drmbuffer: %s: PRIMEDATA create handle for PrimeFD (%d|%i): PrimeFD %i ToHandle %i size %zu modifier %" PRIx64 "",
195 // __FUNCTION__, object, primedata->nb_objects, primedata->objects[object].fd, m_primehandle[object],
196 // primedata->objects[object].size, primedata->objects[object].format_modifier);
197 }
198
199 // fill the planes
200 for (int plane = 0; plane < layer->nb_planes; plane++) {
201 int object = layer->planes[plane].object_index;
203 if (handle) {
205 m_pitch[plane] = layer->planes[plane].pitch;
206 m_offset[plane] = layer->planes[plane].offset;
208 if (primedata->objects[object].format_modifier)
209 modifier[plane] = primedata->objects[object].format_modifier;
210
211 // 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!)",
212 // __FUNCTION__, plane, m_planePrimeHandle[plane], m_objIdx[plane], m_pitch[plane], m_offset[plane], m_size[plane], modifier[plane]);
213 }
214 }
217
218 m_modifier = modifier[0];
219 } else {
221 LOGFATAL("drmbuffer: %s: pixFmt is neither NV12 nor ARGB8888!", __FUNCTION__);
222
223 //LOGDEBUG2(L_DRM, "drmbuffer: %s: %d x %d, pix_fmt %4.4s", __FUNCTION__, m_width, m_height, (char *)&m_pixFmt);
224
226 if (m_pixFmt == DRM_FORMAT_NV12) {
227 creq.height = m_height * 3 / 2;
228 creq.bpp = 8;
229 } else { // DRM_FORMAT_ARGB8888
230 creq.height = m_height;
231 creq.bpp = 32;
232 }
233
234 creq.width = m_width;
235 creq.flags = 0;
236 creq.handle = 0;
237 creq.pitch = 0;
238 creq.size = 0;
239
241 LOGFATAL("drmbuffer: %s: cannot create dumb buffer %dx%d@%d (%d): %m", __FUNCTION__, creq.width, creq.height, creq.bpp, errno);
242
243 struct drm_mode_map_dumb mreq;
244 memset(&mreq, 0, sizeof(struct drm_mode_map_dumb));
245 mreq.handle = creq.handle;
246
248 LOGFATAL("drmbuffer: %s: cannot prepare dumb buffer for mapping (%d): %m", __FUNCTION__, errno);
249
251 if (map == MAP_FAILED)
252 LOGFATAL("drmbuffer: %s: cannot map dumb buffer (%d): %m", __FUNCTION__, errno);
253
254 m_planePrimeHandle[0] = creq.handle;
255 m_pitch[0] = creq.pitch;
256 m_offset[0] = 0;
257 m_size[0] = creq.size;
258 m_pPlane[0] = map;
259 m_numPlanes = 1;
260
261 //LOGDEBUG2(L_DRM, "drmbuffer: %s: fill plane 0: prime handle %d pitch %d offset %d size %d address %p", __FUNCTION__,
262 // m_planePrimeHandle[0], m_pitch[0], m_offset[0], m_size[0], m_pPlane[0]);
263
264 // DRM_FORMAT_NV12 is always using a single buffer object for both planes
265 if (m_pixFmt == DRM_FORMAT_NV12) {
266 m_planePrimeHandle[1] = creq.handle;
267 m_pitch[1] = creq.pitch;
268 m_offset[1] = creq.pitch * m_height;
269 m_size[1] = 0; // shares the buffer object of plane 0
270 m_pPlane[1] = map + m_offset[1];
271 m_numPlanes++;
272 //LOGDEBUG2(L_DRM, "drmbuffer: %s: fill plane 1: prime handle %d pitch %d offset %d size %d address %p", __FUNCTION__,
273 // m_planePrimeHandle[1], m_pitch[1], m_offset[1], m_size[1], m_pPlane[1]);
274 }
275
276 memset(m_pPlane[0], 0, m_size[0]);
277 }
278
279 int ret = -1;
281
282 if (ret) {
283 if (mod_flags)
284 LOGERROR("drmbuffer: %s: cannot create modifiers framebuffer (%d): %m", __FUNCTION__, errno);
285
288 }
289
290 if (ret)
291 LOGFATAL("drmbuffer: %s: cannot create framebuffer (%d): %m", __FUNCTION__, errno);
292
293 LOGDEBUG2(L_DRM, "drmbuffer: %s: Added %sFB fb_id %d width %d height %d pix_fmt %4.4s DMA-BUF handle %d", __FUNCTION__,
294 primedata ? "primedata " : "", m_fbId, m_width, m_height, (char *)&m_pixFmt, m_dmaBufHandle[0]);
295
296 m_dirty = true;
297}
298
303{
304 for (uint32_t i = 0; i < m_width * m_height; ++i) {
305 m_pPlane[0][i] = 0x10;
306 if (i < m_width * m_height / 2)
307 m_pPlane[1][i] = 0x80;
308 }
309}
310
317{
319 m_presentationPending = false;
320
322 Destroy();
323}
324
325/*****************************************************************************
326 * Drm Buffer Pool
327 ****************************************************************************/
328
333{
334 for (const auto &buf : buffer) {
335 if (buf->IsDirty() && buf->DmaBufHandle() == primeFd)
336 return buf.get();
337 }
338
339 return nullptr;
340}
341
346{
347 for (const auto &buf : buffer) {
348 if (!buf->IsDirty())
349 return buf.get();
350 }
351
352 return nullptr;
353}
354
359{
360 for (const auto &buf : buffer) {
361 if (buf->IsDirty() && !buf->IsPresentationPending())
362 return buf.get();
363 }
364
365 return nullptr;
366}
367
375{
376 for (const auto &buf : buffer) {
377 if (buf.get() != exceptBuf && buf->IsDirty()) {
378 av_frame_free(&buf->frame);
379 buf->Destroy();
380 }
381 }
382}
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:33
bool m_dirty
true, if the buffer is dirty (it was written to)
Definition drmbuffer.h:97
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:117
int m_objIdx[4]
index of the objects
Definition drmbuffer.h:106
bool m_closeHandleOnDestroy
true, if DMA-BUF handle should be closed on destroy
Definition drmbuffer.h:118
void Setup(int, uint32_t, uint32_t, uint32_t, AVDRMFrameDescriptor *, bool)
Setup the buffer.
uint64_t m_modifier
Definition drmbuffer.h:114
int m_numObjects
number of prime objects in the buffer
Definition drmbuffer.h:105
uint32_t m_fbId
framebuffer id
Definition drmbuffer.h:99
uint32_t m_width
buffer width
Definition drmbuffer.h:91
uint32_t m_offset[4]
array of the plane offset
Definition drmbuffer.h:111
uint32_t m_pitch[4]
array of the plane pitch
Definition drmbuffer.h:112
void FillBlack(void)
Color the buffer black.
AVFrame * frame
associated AVFrame
Definition drmbuffer.h:84
uint32_t m_objectPrimeHandle[4]
primedata objects prime handles (count is numObjects, index is objIdx)
Definition drmbuffer.h:107
int m_dmaBufHandle[4]
DMA-BUF file descriptor.
Definition drmbuffer.h:104
uint32_t m_pixFmt
buffer pixel format
Definition drmbuffer.h:93
int m_drmDeviceFd
drm device file descriptor
Definition drmbuffer.h:100
uint32_t m_height
buffer height
Definition drmbuffer.h:92
void PresentationFinished(void)
The presentation of this buffer has finished.
bool m_presentationPending
true, if buffer presentation is pending
Definition drmbuffer.h:116
uint8_t * m_pPlane[4]
array of the plane data
Definition drmbuffer.h:109
void Destroy(void)
Clear and destroy the buffer object and its parameters.
Definition drmbuffer.cpp:90
uint32_t m_size[4]
array of the plane size
Definition drmbuffer.h:113
uint32_t m_planePrimeHandle[4]
array of the plane handles
Definition drmbuffer.h:110
int m_numPlanes
number of planes in the buffer
Definition drmbuffer.h:102
std::vector< std::unique_ptr< cDrmBuffer > > buffer
Definition pool.h:24
DRM Buffer Header File.
int plane
#define LOGDEBUG2
log to LOG_DEBUG and add a prefix
Definition logger.h:48
#define LOGERROR
log to LOG_ERR
Definition logger.h:40
#define LOGFATAL
log to LOG_ERR and abort
Definition logger.h:38
@ L_DRM
drm logs
Definition logger.h:64
Logger Header File.
Pool Implementation.