Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
------- init() function --------
monitor_width = m_destRect.Width(); // from kodi
monitor_height = m_destRect.Height(); // from kodi
struct drm_mode_create_dumb dumb_buffer;
/* create dumb buffer */
memset(&dumb_buffer, 0, sizeof(dumb_buffer));
dumb_buffer.width = monitor_width;
dumb_buffer.height = monitor_height;
dumb_buffer.bpp = 32;
ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &dumb_buffer);
if (ret < 0 || !ret.pitch) {
quit error
}
/* do we need to do mmap ?? */
struct drm_mode_map_dumb mreq;
memset(&mreq, 0, sizeof(mreq));
mreq.handle = dumb_buffer.handle;
ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
if (ret) {
quit error
}
// actual mmap
mmap(0, dumb_buffer.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, mreq.offset);
---------- END ----------
CHANGES IN KODI:
void CRendererDRMPRIME::SetVideoPlane(CVideoBufferDRMPRIME* buffer)
{
buffer->m_drm_fd = m_DRM->GetFileDescriptor();
AVDRMFrameDescriptor* descriptor = buffer->GetDescriptor();
if (descriptor && descriptor->nb_layers)
{
uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
uint64_t modifier[4] = {0};
int ret;
// convert Prime FD to GEM handle
for (int object = 0; object < descriptor->nb_objects; object++)
{
ret = drmPrimeFDToHandle(m_DRM->GetFileDescriptor(), descriptor->objects[object].fd, &buffer->m_handles[object]);
if (ret < 0)
{
CLog::Log(LOGERROR, "CRendererDRMPRIME::%s - failed to retrieve the GEM handle from prime fd %d, ret = %d", __FUNCTION__, descriptor->objects[object].fd, ret);
return;
}
}
AVDRMLayerDescriptor* layer = &descriptor->layers[0];
for (int plane = 0; plane < layer->nb_planes; plane++)
{
int object = layer->planes[plane].object_index;
uint32_t handle = buffer->m_handles[object];
if (handle && layer->planes[plane].pitch)
{
handles[plane] = handle;
pitches[plane] = layer->planes[plane].pitch;
offsets[plane] = layer->planes[plane].offset;
modifier[plane] = descriptor->objects[object].format_modifier;
}
}
---------- START IPPv2 job for conversion ----------
not clear: we do this by plane? we should not, since we have only 1 handle and pitch is the same for all planes (=bytesperline)
struct exynos_drm_ipp_std_task task = { };
struct drm_exynos_ioctl_ipp_commit arg = { };
uint32_t id = 0; /* hardcoded first available IPP module */
task.buf[0].id = DRM_EXYNOS_IPP_TASK_BUFFER |
DRM_EXYNOS_IPP_TASK_TYPE_SOURCE;
task.buf[0].fourcc = DRM_FORMAT_NV12;
task.buf[0].width = buffer->GetWidth();
task.buf[0].height = buffer->GetHeight();
task.buf[0].pitch[0] = pitches[0]; // all (2 nv12) planes have the same pitch (bytesperline)
task.buf[0].gem_id[0] = handles[0]; // all (2 nv12) planes have the same handle
task.buf[1].id = DRM_EXYNOS_IPP_TASK_BUFFER |
DRM_EXYNOS_IPP_TASK_TYPE_DESTINATION;
task.buf[1].fourcc = DRM_FORMAT_XRGB8888;
task.buf[1].width = monitor_width; // determined in init()
task.buf[1].height = monitor_height; // determined in init()
task.buf[1].pitch[0] = dumb_buffer.pitch; // dumb_buffer from init()
task.buf[1].gem_id[0] = dumb_buffer.handle;
task.rect[0].id = DRM_EXYNOS_IPP_TASK_RECTANGLE |
DRM_EXYNOS_IPP_TASK_TYPE_SOURCE;
task.rect[0].x = 0;
task.rect[0].y = 0;
task.rect[0].w = buffer->GetWidth();
task.rect[0].h = buffer->GetHeight();
task.rect[1].id = DRM_EXYNOS_IPP_TASK_RECTANGLE |
DRM_EXYNOS_IPP_TASK_TYPE_DESTINATION;
task.rect[1].x = 0;
task.rect[1].y = 0;
task.rect[1].w = monitor_width;
task.rect[1].h = monitor_height;
task.transform.id = DRM_EXYNOS_IPP_TASK_TRANSFORM;
task.transform.rotation = DRM_MODE_ROTATE_0; // there is no rotation
// but we have different width/height and fourcc
// so it should do transform and scale, right ?
arg.flags = 0;
arg.ipp_id = id;
arg.params_size = sizeof(task);
arg.params_ptr = (unsigned long)(&task);
arg.user_data = 0;
if (drmCommandWriteRead(fd, DRM_EXYNOS_IPP_COMMIT, &arg, sizeof(arg))) {
fprintf(stderr, "failed to commit Exynos IPP task (%d): %m\n",
errno);
return errno;
}
---------- END ----------
// add the video frame FB
// ret = drmModeAddFB2WithModifiers(m_DRM->GetFileDescriptor(), buffer->GetWidth(), buffer->GetHeight(), layer->format, handles, pitches, offsets, modifier, &buffer->m_fb_id, 0);
// we add our own buffer not the one received from FFMPEG
// we still use "buffer->m_fb_id" to store the returned *buf_id, since we pretend we are displaying "buffer" not our own "dumb_buffer"
// also we lose the modifiers, and send NULL instead; offset is 0 .... XRGB has 1 plane only
!! ret = drmModeAddFB2WithModifiers(m_DRM->GetFileDescriptor(), monitor_width, monitor_height, DRM_FORMAT_XRGB8888, [dumb_buffer.handle], [dumb_buffer.pitch], [0], NULL, &buffer->m_fb_id, 0);
if (ret < 0)
{
CLog::Log(LOGERROR, "CRendererDRMPRIME::%s - failed to add drm layer %d, ret = %d", __FUNCTION__, buffer->m_fb_id, ret);
return;
}
int32_t crtc_x = static_cast<int32_t>(m_destRect.x1) & ~1;
int32_t crtc_y = static_cast<int32_t>(m_destRect.y1) & ~1;
uint32_t crtc_w = (static_cast<uint32_t>(m_destRect.Width()) + 1) & ~1;
uint32_t crtc_h = (static_cast<uint32_t>(m_destRect.Height()) + 1) & ~1;
uint32_t src_x = 0;
uint32_t src_y = 0;
!! uint32_t src_w = monitor_width << 16; //buffer->GetWidth() << 16;
!! uint32_t src_h = monitor_height << 16; //buffer->GetHeight() << 16;
m_DRM->AddProperty(m_DRM->GetPrimaryPlane(), "FB_ID", buffer->m_fb_id);
m_DRM->AddProperty(m_DRM->GetPrimaryPlane(), "CRTC_ID", m_DRM->GetCrtc()->crtc->crtc_id);
m_DRM->AddProperty(m_DRM->GetPrimaryPlane(), "SRC_X", src_x);
m_DRM->AddProperty(m_DRM->GetPrimaryPlane(), "SRC_Y", src_y);
m_DRM->AddProperty(m_DRM->GetPrimaryPlane(), "SRC_W", src_w);
m_DRM->AddProperty(m_DRM->GetPrimaryPlane(), "SRC_H", src_h);
m_DRM->AddProperty(m_DRM->GetPrimaryPlane(), "CRTC_X", crtc_x);
m_DRM->AddProperty(m_DRM->GetPrimaryPlane(), "CRTC_Y", crtc_y);
m_DRM->AddProperty(m_DRM->GetPrimaryPlane(), "CRTC_W", crtc_w);
m_DRM->AddProperty(m_DRM->GetPrimaryPlane(), "CRTC_H", crtc_h);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment