drm: helper to get the primary plane

This commit is contained in:
Rémi Denis-Courmont 2022-03-20 23:09:38 +02:00 committed by Hugo Beauzée-Luyssen
parent 82056aa6da
commit 3aa9536985
2 changed files with 148 additions and 0 deletions

View File

@ -26,10 +26,18 @@
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <drm_mode.h>
#include <vlc_common.h>
#include "vlc_drm.h"
enum { /* DO NOT CHANGE. MUST MATCH KERNEL ABI. */
VLC_DRM_PLANE_TYPE_OVERLAY=0,
VLC_DRM_PLANE_TYPE_PRIMARY=1,
VLC_DRM_PLANE_TYPE_CURSOR=2,
};
int vlc_drm_get_crtc_index(int fd, uint_fast32_t crtc_id)
{
uint32_t crtcs[32];
@ -53,3 +61,134 @@ int vlc_drm_get_crtc_index(int fd, uint_fast32_t crtc_id)
errno = ENXIO;
return -1;
}
static bool vlc_drm_prop_match(int fd, uint_fast32_t pid, const char *name)
{
struct drm_mode_get_property prop = {
.prop_id = pid,
};
if (vlc_drm_ioctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop) < 0)
return false;
return strcmp(name, prop.name) == 0;
}
static int vlc_drm_get_prop(int fd, uint_fast32_t oid, uint_fast32_t tid,
const char *name, uint64_t *restrict valp)
{
struct drm_mode_obj_get_properties counter = {
.obj_id = oid,
.obj_type = tid,
};
int ret = -1;
if (vlc_drm_ioctl(fd, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, &counter) < 0)
return -1;
size_t count = counter.count_props;
uint32_t *ids = vlc_alloc(count, sizeof (*ids));
uint64_t *values = vlc_alloc(count, sizeof (*values));
if (unlikely(ids == NULL || values == NULL))
goto out;
struct drm_mode_obj_get_properties props = {
.props_ptr = (uintptr_t)(void *)ids,
.prop_values_ptr = (uintptr_t)(void *)values,
.count_props = count,
.obj_id = oid,
.obj_type = tid,
};
if (vlc_drm_ioctl(fd, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, &props) < 0)
goto out;
if (unlikely(count < props.count_props)) {
/*
* Properties should not be created asynchronously. It could
* theoretically occur if the underlying object was hot-unplugged, then
* different object with the same type was hot-plugged and got the same
* object identifier. But if so, everything we thought we knew till now
* has potentially become invalid, so we might as well fail safely.
*/
errno = ENOBUFS;
goto out;
}
/* NOTE: if more than one property is needed, rethink this function */
for (size_t i = 0; i < props.count_props; i++) {
if (vlc_drm_prop_match(fd, ids[i], name)) {
*valp = values[i];
ret = 0;
goto out;
}
}
errno = ENXIO;
out:
free(values);
free(ids);
return ret;
}
static int vlc_drm_get_plane_prop(int fd, uint_fast32_t plane,
const char *name, uint64_t *restrict valp)
{
return vlc_drm_get_prop(fd, plane, DRM_MODE_OBJECT_PLANE, name, valp);
}
static ssize_t vlc_drm_get_planes(int fd, uint32_t **restrict listp)
{
size_t count = 32;
for (;;) {
uint32_t *planes = vlc_alloc(count, sizeof (*planes));
if (unlikely(planes == NULL))
return -1;
struct drm_mode_get_plane_res res = {
.plane_id_ptr = (uintptr_t)(void *)planes,
.count_planes = count,
};
if (vlc_drm_ioctl(fd, DRM_IOCTL_MODE_GETPLANERESOURCES, &res) < 0) {
free(planes);
return -1;
}
if (likely(count >= res.count_planes)) {
*listp = planes;
return res.count_planes;
}
free(planes);
}
}
uint_fast32_t vlc_drm_get_crtc_primary_plane(int fd, unsigned int idx)
{
assert(idx < 32); /* Don't mix up object IDs and indices! */
uint32_t *planes;
ssize_t count = vlc_drm_get_planes(fd, &planes);
if (count < 0)
return -1;
uint_fast32_t ret = 0;
for (ssize_t i = 0; i < count; i++) {
struct drm_mode_get_plane plane = {
.plane_id = planes[i],
};
uint64_t planetype;
if (vlc_drm_ioctl(fd, DRM_IOCTL_MODE_GETPLANE, &plane) >= 0
&& ((plane.possible_crtcs >> idx) & 1)
&& vlc_drm_get_plane_prop(fd, planes[i], "type", &planetype) == 0
&& planetype == VLC_DRM_PLANE_TYPE_PRIMARY) {
ret = planes[i];
goto out;
}
}
errno = ENXIO;
out:
free(planes);
return ret;
}

View File

@ -97,6 +97,15 @@ uint32_t vlc_drm_dumb_get_fb_id(const picture_t *pic);
*/
int vlc_drm_get_crtc_index(int fd, uint_fast32_t crtc_id);
/**
* Finds the primary plane of a CRTC.
*
* \param fd DRM device file descriptor
* \param idx CRTC object index (as returned by vlc_drm_get_crtc_index())
* \return the primary plane object ID or zero on error
*/
uint_fast32_t vlc_drm_get_crtc_primary_plane(int fd, unsigned int idx);
static inline int vlc_drm_ioctl(int fd, unsigned long cmd, void *argp)
{
int ret;