2021-12-29 12:08:12 +01:00
|
|
|
#include <drm_fourcc.h>
|
2019-12-10 10:45:22 +01:00
|
|
|
#include <gbm.h>
|
|
|
|
#include <sys/mman.h>
|
2021-12-29 12:08:12 +01:00
|
|
|
#include <unistd.h>
|
2019-12-10 10:45:22 +01:00
|
|
|
#include <xf86drm.h>
|
|
|
|
#include <xf86drmMode.h>
|
|
|
|
|
2021-12-29 12:08:12 +01:00
|
|
|
#define DRM_DEBUG
|
2019-12-10 10:45:22 +01:00
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
// DRM
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
2021-12-29 12:08:12 +01:00
|
|
|
struct _Drm_Render_ {
|
2019-12-10 10:45:22 +01:00
|
|
|
int fd_drm;
|
|
|
|
drmModeModeInfo mode;
|
|
|
|
drmModeCrtc *saved_crtc;
|
2021-12-29 12:08:12 +01:00
|
|
|
// drmEventContext ev;
|
2019-12-10 10:45:22 +01:00
|
|
|
int bpp;
|
|
|
|
uint32_t connector_id, crtc_id, video_plane;
|
|
|
|
uint32_t hdr_metadata;
|
2021-12-29 12:08:12 +01:00
|
|
|
uint32_t mmWidth, mmHeight; // Size in mm
|
2021-03-16 09:40:08 +01:00
|
|
|
uint32_t hdr_blob_id;
|
2019-12-10 10:45:22 +01:00
|
|
|
};
|
|
|
|
typedef struct _Drm_Render_ VideoRender;
|
|
|
|
|
|
|
|
struct {
|
|
|
|
struct gbm_device *dev;
|
|
|
|
struct gbm_surface *surface;
|
|
|
|
} gbm;
|
|
|
|
|
|
|
|
VideoRender *render;
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
// Helper functions
|
|
|
|
//----------------------------------------------------------------------------
|
2019-12-17 12:15:35 +01:00
|
|
|
#ifndef ARRAY_SIZE
|
|
|
|
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
|
|
|
#endif
|
|
|
|
struct type_name {
|
|
|
|
unsigned int type;
|
|
|
|
const char *name;
|
|
|
|
};
|
|
|
|
|
2021-12-29 12:08:12 +01:00
|
|
|
static const char *util_lookup_type_name(unsigned int type, const struct type_name *table, unsigned int count) {
|
2019-12-17 12:15:35 +01:00
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
if (table[i].type == type)
|
|
|
|
return table[i].name;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct type_name connector_type_names[] = {
|
2021-12-29 12:08:12 +01:00
|
|
|
{DRM_MODE_CONNECTOR_Unknown, "unknown"},
|
|
|
|
{DRM_MODE_CONNECTOR_VGA, "VGA"},
|
|
|
|
{DRM_MODE_CONNECTOR_DVII, "DVI-I"},
|
|
|
|
{DRM_MODE_CONNECTOR_DVID, "DVI-D"},
|
|
|
|
{DRM_MODE_CONNECTOR_DVIA, "DVI-A"},
|
|
|
|
{DRM_MODE_CONNECTOR_Composite, "composite"},
|
|
|
|
{DRM_MODE_CONNECTOR_SVIDEO, "s-video"},
|
|
|
|
{DRM_MODE_CONNECTOR_LVDS, "LVDS"},
|
|
|
|
{DRM_MODE_CONNECTOR_Component, "component"},
|
|
|
|
{DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN"},
|
|
|
|
{DRM_MODE_CONNECTOR_DisplayPort, "DP"},
|
|
|
|
{DRM_MODE_CONNECTOR_HDMIA, "HDMI-A"},
|
|
|
|
{DRM_MODE_CONNECTOR_HDMIB, "HDMI-B"},
|
|
|
|
{DRM_MODE_CONNECTOR_TV, "TV"},
|
|
|
|
{DRM_MODE_CONNECTOR_eDP, "eDP"},
|
|
|
|
{DRM_MODE_CONNECTOR_VIRTUAL, "Virtual"},
|
|
|
|
{DRM_MODE_CONNECTOR_DSI, "DSI"},
|
|
|
|
{DRM_MODE_CONNECTOR_DPI, "DPI"},
|
2019-12-17 12:15:35 +01:00
|
|
|
};
|
|
|
|
|
2021-12-29 12:08:12 +01:00
|
|
|
const char *util_lookup_connector_type_name(unsigned int type) {
|
|
|
|
return util_lookup_type_name(type, connector_type_names, ARRAY_SIZE(connector_type_names));
|
2019-12-17 12:15:35 +01:00
|
|
|
}
|
2019-12-10 10:45:22 +01:00
|
|
|
|
2021-12-29 12:08:12 +01:00
|
|
|
static uint64_t GetPropertyValue(int fd_drm, uint32_t objectID, uint32_t objectType, const char *propName) {
|
2019-12-10 10:45:22 +01:00
|
|
|
uint32_t i;
|
|
|
|
int found = 0;
|
|
|
|
uint64_t value = 0;
|
|
|
|
drmModePropertyPtr Prop;
|
2021-12-29 12:08:12 +01:00
|
|
|
drmModeObjectPropertiesPtr objectProps = drmModeObjectGetProperties(fd_drm, objectID, objectType);
|
2019-12-10 10:45:22 +01:00
|
|
|
|
|
|
|
for (i = 0; i < objectProps->count_props; i++) {
|
|
|
|
if ((Prop = drmModeGetProperty(fd_drm, objectProps->props[i])) == NULL)
|
|
|
|
fprintf(stderr, "GetPropertyValue: Unable to query property.\n");
|
|
|
|
|
|
|
|
if (strcmp(propName, Prop->name) == 0) {
|
|
|
|
value = objectProps->prop_values[i];
|
|
|
|
found = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
drmModeFreeProperty(Prop);
|
|
|
|
|
|
|
|
if (found)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
drmModeFreeObjectProperties(objectProps);
|
|
|
|
|
|
|
|
#ifdef DRM_DEBUG
|
|
|
|
if (!found)
|
2021-12-29 12:08:12 +01:00
|
|
|
fprintf(stderr, "GetPropertyValue: Unable to find value for property \'%s\'.\n", propName);
|
2019-12-10 10:45:22 +01:00
|
|
|
#endif
|
|
|
|
return value;
|
|
|
|
}
|
2021-12-29 12:08:12 +01:00
|
|
|
static uint32_t GetPropertyID(int fd_drm, uint32_t objectID, uint32_t objectType, const char *propName) {
|
2019-12-10 10:45:22 +01:00
|
|
|
uint32_t i;
|
|
|
|
int found = 0;
|
|
|
|
uint32_t value = -1;
|
|
|
|
drmModePropertyPtr Prop;
|
2021-12-29 12:08:12 +01:00
|
|
|
drmModeObjectPropertiesPtr objectProps = drmModeObjectGetProperties(fd_drm, objectID, objectType);
|
2019-12-10 10:45:22 +01:00
|
|
|
|
|
|
|
for (i = 0; i < objectProps->count_props; i++) {
|
|
|
|
if ((Prop = drmModeGetProperty(fd_drm, objectProps->props[i])) == NULL)
|
|
|
|
fprintf(stderr, "GetPropertyValue: Unable to query property.\n");
|
|
|
|
|
|
|
|
if (strcmp(propName, Prop->name) == 0) {
|
|
|
|
value = objectProps->props[i];
|
|
|
|
found = 1;
|
|
|
|
}
|
|
|
|
drmModeFreeProperty(Prop);
|
|
|
|
if (found)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
drmModeFreeObjectProperties(objectProps);
|
|
|
|
|
|
|
|
#ifdef DRM_DEBUG
|
|
|
|
if (!found)
|
2021-12-29 12:08:12 +01:00
|
|
|
Debug(3, "GetPropertyValue: Unable to find ID for property \'%s\'.\n", propName);
|
2019-12-10 10:45:22 +01:00
|
|
|
#endif
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2021-12-29 12:08:12 +01:00
|
|
|
static int SetPropertyRequest(drmModeAtomicReqPtr ModeReq, int fd_drm, uint32_t objectID, uint32_t objectType,
|
|
|
|
const char *propName, uint64_t value) {
|
2019-12-10 10:45:22 +01:00
|
|
|
uint32_t i;
|
|
|
|
uint64_t id = 0;
|
|
|
|
drmModePropertyPtr Prop;
|
2021-12-29 12:08:12 +01:00
|
|
|
drmModeObjectPropertiesPtr objectProps = drmModeObjectGetProperties(fd_drm, objectID, objectType);
|
2019-12-10 10:45:22 +01:00
|
|
|
|
|
|
|
for (i = 0; i < objectProps->count_props; i++) {
|
|
|
|
if ((Prop = drmModeGetProperty(fd_drm, objectProps->props[i])) == NULL)
|
2021-12-29 12:08:12 +01:00
|
|
|
printf("SetPropertyRequest: Unable to query property.\n");
|
2019-12-10 10:45:22 +01:00
|
|
|
|
|
|
|
if (strcmp(propName, Prop->name) == 0) {
|
|
|
|
id = Prop->prop_id;
|
|
|
|
drmModeFreeProperty(Prop);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
drmModeFreeProperty(Prop);
|
|
|
|
}
|
|
|
|
|
|
|
|
drmModeFreeObjectProperties(objectProps);
|
|
|
|
|
|
|
|
if (id == 0)
|
2021-12-29 12:08:12 +01:00
|
|
|
printf("SetPropertyRequest: Unable to find value for property \'%s\'.\n", propName);
|
2019-12-10 10:45:22 +01:00
|
|
|
|
|
|
|
return drmModeAtomicAddProperty(ModeReq, objectID, id, value);
|
|
|
|
}
|
|
|
|
|
2020-01-31 12:28:18 +01:00
|
|
|
static void CuvidSetVideoMode(void);
|
2021-12-29 12:08:12 +01:00
|
|
|
void set_video_mode(int width, int height) {
|
2021-03-16 09:40:08 +01:00
|
|
|
drmModeConnector *connector;
|
|
|
|
drmModeModeInfo *mode;
|
|
|
|
int ii;
|
|
|
|
if (height != 1080 && height != 2160)
|
|
|
|
return;
|
|
|
|
connector = drmModeGetConnector(render->fd_drm, render->connector_id);
|
|
|
|
for (ii = 0; ii < connector->count_modes; ii++) {
|
|
|
|
mode = &connector->modes[ii];
|
2021-12-29 12:08:12 +01:00
|
|
|
printf("Mode %d %dx%d Rate %d\n", ii, mode->hdisplay, mode->vdisplay, mode->vrefresh);
|
|
|
|
if (width == mode->hdisplay && height == mode->vdisplay && mode->vrefresh == DRMRefresh &&
|
|
|
|
render->mode.hdisplay != width && render->mode.vdisplay != height &&
|
|
|
|
!(mode->flags & DRM_MODE_FLAG_INTERLACE)) {
|
2021-03-16 09:40:08 +01:00
|
|
|
memcpy(&render->mode, mode, sizeof(drmModeModeInfo));
|
|
|
|
VideoWindowWidth = mode->hdisplay;
|
2020-01-31 12:28:18 +01:00
|
|
|
VideoWindowHeight = mode->vdisplay;
|
2021-12-29 12:08:12 +01:00
|
|
|
eglDestroySurface(eglDisplay, eglSurface);
|
2021-03-16 09:40:08 +01:00
|
|
|
EglCheck();
|
2021-12-29 12:08:12 +01:00
|
|
|
gbm_surface_destroy(gbm.surface);
|
2021-03-16 09:40:08 +01:00
|
|
|
InitBo(render->bpp);
|
|
|
|
CuvidSetVideoMode();
|
2021-12-29 12:08:12 +01:00
|
|
|
Debug(3, "Set new mode %d:%d\n", mode->hdisplay, mode->vdisplay);
|
2021-03-16 09:40:08 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-01-31 12:28:18 +01:00
|
|
|
}
|
|
|
|
|
2021-12-29 12:08:12 +01:00
|
|
|
static int FindDevice(VideoRender *render) {
|
2019-12-10 10:45:22 +01:00
|
|
|
drmVersion *version;
|
|
|
|
drmModeRes *resources;
|
|
|
|
drmModeConnector *connector;
|
|
|
|
drmModeEncoder *encoder = 0;
|
|
|
|
drmModeModeInfo *mode;
|
|
|
|
drmModePlane *plane;
|
|
|
|
drmModePlaneRes *plane_res;
|
|
|
|
drmModeObjectPropertiesPtr props;
|
|
|
|
uint32_t j, k;
|
|
|
|
uint64_t has_dumb;
|
|
|
|
uint64_t has_prime;
|
2021-12-29 12:08:12 +01:00
|
|
|
int i, ii = 0;
|
2019-12-17 12:15:35 +01:00
|
|
|
char connectorstr[10];
|
|
|
|
int found = 0;
|
2021-03-16 09:40:08 +01:00
|
|
|
render->fd_drm = open("/dev/dri/card0", O_RDWR);
|
2019-12-10 10:45:22 +01:00
|
|
|
if (render->fd_drm < 0) {
|
|
|
|
fprintf(stderr, "FindDevice: cannot open /dev/dri/card0: %m\n");
|
|
|
|
return -errno;
|
|
|
|
}
|
2021-12-29 12:08:12 +01:00
|
|
|
|
2021-03-16 09:40:08 +01:00
|
|
|
int ret = drmSetMaster(render->fd_drm);
|
2021-12-29 12:08:12 +01:00
|
|
|
|
|
|
|
if (ret < 0) {
|
2021-03-16 09:40:08 +01:00
|
|
|
drm_magic_t magic;
|
|
|
|
|
|
|
|
ret = drmGetMagic(render->fd_drm, &magic);
|
2021-12-29 12:08:12 +01:00
|
|
|
if (ret < 0) {
|
|
|
|
Debug(3, "drm:%s - failed to get drm magic: %s\n", __FUNCTION__, strerror(errno));
|
|
|
|
return -1;
|
2021-03-16 09:40:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = drmAuthMagic(render->fd_drm, magic);
|
2021-12-29 12:08:12 +01:00
|
|
|
if (ret < 0) {
|
|
|
|
Debug(3, "drm:%s - failed to authorize drm magic: %s\n", __FUNCTION__, strerror(errno));
|
|
|
|
return -1;
|
2021-03-16 09:40:08 +01:00
|
|
|
}
|
|
|
|
}
|
2021-12-29 12:08:12 +01:00
|
|
|
|
2019-12-10 10:45:22 +01:00
|
|
|
version = drmGetVersion(render->fd_drm);
|
2021-12-29 12:08:12 +01:00
|
|
|
fprintf(stderr, "FindDevice: open /dev/dri/card0: %s\n", version->name);
|
2020-04-10 16:17:23 +02:00
|
|
|
|
2019-12-17 12:15:35 +01:00
|
|
|
// check capability
|
|
|
|
if (drmGetCap(render->fd_drm, DRM_CAP_DUMB_BUFFER, &has_dumb) < 0 || has_dumb == 0)
|
|
|
|
fprintf(stderr, "FindDevice: drmGetCap DRM_CAP_DUMB_BUFFER failed or doesn't have dumb buffer\n");
|
2019-12-10 10:45:22 +01:00
|
|
|
|
2019-12-17 12:15:35 +01:00
|
|
|
if (drmSetClientCap(render->fd_drm, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) != 0)
|
|
|
|
fprintf(stderr, "FindDevice: DRM_CLIENT_CAP_UNIVERSAL_PLANES not available.\n");
|
2019-12-10 10:45:22 +01:00
|
|
|
|
2019-12-17 12:15:35 +01:00
|
|
|
if (drmSetClientCap(render->fd_drm, DRM_CLIENT_CAP_ATOMIC, 1) != 0)
|
|
|
|
fprintf(stderr, "FindDevice: DRM_CLIENT_CAP_ATOMIC not available.\n");
|
2019-12-10 10:45:22 +01:00
|
|
|
|
2019-12-17 12:15:35 +01:00
|
|
|
if (drmGetCap(render->fd_drm, DRM_CAP_PRIME, &has_prime) < 0)
|
|
|
|
fprintf(stderr, "FindDevice: DRM_CAP_PRIME not available.\n");
|
2019-12-10 10:45:22 +01:00
|
|
|
|
2019-12-17 12:15:35 +01:00
|
|
|
if (drmGetCap(render->fd_drm, DRM_PRIME_CAP_EXPORT, &has_prime) < 0)
|
|
|
|
fprintf(stderr, "FindDevice: DRM_PRIME_CAP_EXPORT not available.\n");
|
2019-12-10 10:45:22 +01:00
|
|
|
|
2019-12-17 12:15:35 +01:00
|
|
|
if (drmGetCap(render->fd_drm, DRM_PRIME_CAP_IMPORT, &has_prime) < 0)
|
|
|
|
fprintf(stderr, "FindDevice: DRM_PRIME_CAP_IMPORT not available.\n");
|
2020-04-10 16:17:23 +02:00
|
|
|
|
2021-12-29 12:08:12 +01:00
|
|
|
if ((resources = drmModeGetResources(render->fd_drm)) == NULL) {
|
2019-12-10 10:45:22 +01:00
|
|
|
fprintf(stderr, "FindDevice: cannot retrieve DRM resources (%d): %m\n", errno);
|
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
2021-12-29 12:08:12 +01:00
|
|
|
Debug(3, "[FindDevice] DRM have %i connectors, %i crtcs, %i encoders\n", resources->count_connectors,
|
|
|
|
resources->count_crtcs, resources->count_encoders);
|
2019-12-10 10:45:22 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
// find all available connectors
|
|
|
|
for (i = 0; i < resources->count_connectors; i++) {
|
|
|
|
connector = drmModeGetConnector(render->fd_drm, resources->connectors[i]);
|
|
|
|
if (!connector) {
|
|
|
|
fprintf(stderr, "FindDevice: cannot retrieve DRM connector (%d): %m\n", errno);
|
2019-12-17 12:15:35 +01:00
|
|
|
return -errno;
|
2019-12-10 10:45:22 +01:00
|
|
|
}
|
2020-04-10 16:17:23 +02:00
|
|
|
|
2021-12-29 12:08:12 +01:00
|
|
|
sprintf(connectorstr, "%s-%u", util_lookup_connector_type_name(connector->connector_type),
|
|
|
|
connector->connector_type_id);
|
|
|
|
printf("Connector >%s< is %sconnected\n", connectorstr,
|
|
|
|
connector->connection == DRM_MODE_CONNECTED ? "" : "not ");
|
|
|
|
if (DRMConnector && strcmp(DRMConnector, connectorstr))
|
2019-12-17 12:15:35 +01:00
|
|
|
continue;
|
2020-04-10 16:17:23 +02:00
|
|
|
|
2019-12-10 10:45:22 +01:00
|
|
|
if (connector->connection == DRM_MODE_CONNECTED && connector->count_modes > 0) {
|
2021-03-16 09:40:08 +01:00
|
|
|
float aspect = (float)connector->mmWidth / (float)connector->mmHeight;
|
|
|
|
if ((aspect > 1.70) && (aspect < 1.85)) {
|
2021-12-29 12:08:12 +01:00
|
|
|
render->mmHeight = 90;
|
|
|
|
render->mmWidth = 160;
|
2021-03-16 09:40:08 +01:00
|
|
|
} else {
|
2021-12-29 12:08:12 +01:00
|
|
|
render->mmHeight = connector->mmHeight;
|
|
|
|
render->mmWidth = connector->mmWidth;
|
2021-03-16 09:40:08 +01:00
|
|
|
}
|
|
|
|
render->connector_id = connector->connector_id;
|
2019-12-10 10:45:22 +01:00
|
|
|
// FIXME: use default encoder/crtc pair
|
2021-12-29 12:08:12 +01:00
|
|
|
if ((encoder = drmModeGetEncoder(render->fd_drm, connector->encoder_id)) == NULL) {
|
2019-12-10 10:45:22 +01:00
|
|
|
fprintf(stderr, "FindDevice: cannot retrieve encoder (%d): %m\n", errno);
|
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
render->crtc_id = encoder->crtc_id;
|
2020-04-10 16:17:23 +02:00
|
|
|
|
2021-12-29 12:08:12 +01:00
|
|
|
render->hdr_metadata = GetPropertyID(render->fd_drm, connector->connector_id, DRM_MODE_OBJECT_CONNECTOR,
|
|
|
|
"HDR_OUTPUT_METADATA");
|
|
|
|
printf("ID %d of METADATA in Connector %d connected %d\n", render->hdr_metadata, connector->connector_id,
|
|
|
|
connector->connection);
|
2020-04-10 16:17:23 +02:00
|
|
|
|
2021-12-29 12:08:12 +01:00
|
|
|
memcpy(&render->mode, &connector->modes[0], sizeof(drmModeModeInfo)); // set fallback
|
2019-12-17 12:15:35 +01:00
|
|
|
// search Modes for Connector
|
|
|
|
for (ii = 0; ii < connector->count_modes; ii++) {
|
|
|
|
mode = &connector->modes[ii];
|
2020-04-10 16:17:23 +02:00
|
|
|
|
2021-12-29 12:08:12 +01:00
|
|
|
printf("Mode %d %dx%d Rate %d\n", ii, mode->hdisplay, mode->vdisplay, mode->vrefresh);
|
2020-04-10 16:17:23 +02:00
|
|
|
|
|
|
|
if (VideoWindowWidth && VideoWindowHeight) { // preset by command line
|
2021-12-29 12:08:12 +01:00
|
|
|
if (VideoWindowWidth == mode->hdisplay && VideoWindowHeight == mode->vdisplay &&
|
|
|
|
mode->vrefresh == DRMRefresh && !(mode->flags & DRM_MODE_FLAG_INTERLACE)) {
|
2019-12-17 12:15:35 +01:00
|
|
|
memcpy(&render->mode, mode, sizeof(drmModeModeInfo));
|
|
|
|
break;
|
|
|
|
}
|
2021-12-29 12:08:12 +01:00
|
|
|
} else {
|
2019-12-17 12:15:35 +01:00
|
|
|
if (!(mode->flags & DRM_MODE_FLAG_INTERLACE)) {
|
|
|
|
memcpy(&render->mode, mode, sizeof(drmModeModeInfo));
|
|
|
|
VideoWindowWidth = mode->hdisplay;
|
|
|
|
VideoWindowHeight = mode->vdisplay;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
found = 1;
|
2021-12-29 12:08:12 +01:00
|
|
|
i = resources->count_connectors; // uuuuhh
|
2019-12-17 12:15:35 +01:00
|
|
|
}
|
|
|
|
VideoWindowWidth = render->mode.hdisplay;
|
|
|
|
VideoWindowHeight = render->mode.vdisplay;
|
|
|
|
if (found)
|
2021-12-29 12:08:12 +01:00
|
|
|
printf("Use Mode %d %dx%d Rate %d\n", ii, render->mode.hdisplay, render->mode.vdisplay,
|
|
|
|
render->mode.vrefresh);
|
2019-12-10 10:45:22 +01:00
|
|
|
drmModeFreeConnector(connector);
|
|
|
|
}
|
2019-12-17 12:15:35 +01:00
|
|
|
if (!found) {
|
2021-12-29 12:08:12 +01:00
|
|
|
Debug(3, "Requested Connector not found or not connected\n");
|
2019-12-17 12:15:35 +01:00
|
|
|
printf("Requested Connector not found or not connected\n");
|
|
|
|
return -1;
|
|
|
|
}
|
2020-04-10 16:17:23 +02:00
|
|
|
|
2019-12-10 10:45:22 +01:00
|
|
|
// find first plane
|
|
|
|
if ((plane_res = drmModeGetPlaneResources(render->fd_drm)) == NULL)
|
|
|
|
fprintf(stderr, "FindDevice: cannot retrieve PlaneResources (%d): %m\n", errno);
|
|
|
|
|
|
|
|
for (j = 0; j < plane_res->count_planes; j++) {
|
|
|
|
plane = drmModeGetPlane(render->fd_drm, plane_res->planes[j]);
|
|
|
|
|
|
|
|
if (plane == NULL)
|
|
|
|
fprintf(stderr, "FindDevice: cannot query DRM-KMS plane %d\n", j);
|
|
|
|
|
|
|
|
for (i = 0; i < resources->count_crtcs; i++) {
|
|
|
|
if (plane->possible_crtcs & (1 << i))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2021-12-29 12:08:12 +01:00
|
|
|
uint64_t type = GetPropertyValue(render->fd_drm, plane_res->planes[j], DRM_MODE_OBJECT_PLANE, "type");
|
2020-04-10 16:17:23 +02:00
|
|
|
uint64_t zpos = 0;
|
2019-12-10 10:45:22 +01:00
|
|
|
|
|
|
|
#ifdef DRM_DEBUG // If more then 2 crtcs this must rewriten!!!
|
2021-12-29 12:08:12 +01:00
|
|
|
printf("[FindDevice] Plane id %i crtc_id %i possible_crtcs %i possible CRTC %i type %s\n", plane->plane_id,
|
|
|
|
plane->crtc_id, plane->possible_crtcs, resources->crtcs[i],
|
|
|
|
(type == DRM_PLANE_TYPE_PRIMARY) ? "primary plane"
|
|
|
|
: (type == DRM_PLANE_TYPE_OVERLAY) ? "overlay plane"
|
|
|
|
: (type == DRM_PLANE_TYPE_CURSOR) ? "cursor plane"
|
|
|
|
: "No plane type");
|
2019-12-10 10:45:22 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
// test pixel format and plane caps
|
|
|
|
for (k = 0; k < plane->count_formats; k++) {
|
|
|
|
if (encoder->possible_crtcs & plane->possible_crtcs) {
|
|
|
|
switch (plane->formats[k]) {
|
2021-03-16 09:40:08 +01:00
|
|
|
case DRM_FORMAT_XRGB2101010:
|
2019-12-10 10:45:22 +01:00
|
|
|
if (!render->video_plane) {
|
|
|
|
render->video_plane = plane->plane_id;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
drmModeFreePlane(plane);
|
|
|
|
}
|
|
|
|
|
|
|
|
drmModeFreePlaneResources(plane_res);
|
|
|
|
|
|
|
|
drmModeFreeEncoder(encoder);
|
|
|
|
drmModeFreeResources(resources);
|
|
|
|
|
|
|
|
#ifdef DRM_DEBUG
|
2021-12-29 12:08:12 +01:00
|
|
|
printf("[FindDevice] DRM setup CRTC: %i video_plane: %i \n", render->crtc_id, render->video_plane);
|
2019-12-10 10:45:22 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
// save actual modesetting
|
|
|
|
render->saved_crtc = drmModeGetCrtc(render->fd_drm, render->crtc_id);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
///
|
|
|
|
/// Initialize video output module.
|
|
|
|
///
|
2021-12-29 12:08:12 +01:00
|
|
|
void VideoInitDrm() {
|
2019-12-10 10:45:22 +01:00
|
|
|
int i;
|
2020-04-10 16:17:23 +02:00
|
|
|
|
2019-12-10 10:45:22 +01:00
|
|
|
if (!(render = calloc(1, sizeof(*render)))) {
|
2019-12-17 12:15:35 +01:00
|
|
|
Fatal(_("video/DRM: out of memory\n"));
|
2019-12-10 10:45:22 +01:00
|
|
|
return;
|
|
|
|
}
|
2020-04-10 16:17:23 +02:00
|
|
|
|
2021-12-29 12:08:12 +01:00
|
|
|
if (FindDevice(render)) {
|
|
|
|
Fatal(_("VideoInit: FindDevice() failed\n"));
|
2019-12-10 10:45:22 +01:00
|
|
|
}
|
2020-04-10 16:17:23 +02:00
|
|
|
|
2021-12-29 12:08:12 +01:00
|
|
|
gbm.dev = gbm_create_device(render->fd_drm);
|
|
|
|
assert(gbm.dev != NULL);
|
2020-04-10 16:17:23 +02:00
|
|
|
|
2019-12-10 10:45:22 +01:00
|
|
|
PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display = NULL;
|
2021-03-16 09:40:08 +01:00
|
|
|
|
2021-12-29 12:08:12 +01:00
|
|
|
get_platform_display = (void *)eglGetProcAddress("eglGetPlatformDisplayEXT");
|
2019-12-10 10:45:22 +01:00
|
|
|
assert(get_platform_display != NULL);
|
2020-04-10 16:17:23 +02:00
|
|
|
|
2019-12-10 10:45:22 +01:00
|
|
|
eglDisplay = get_platform_display(EGL_PLATFORM_GBM_KHR, gbm.dev, NULL);
|
|
|
|
|
2021-03-16 09:40:08 +01:00
|
|
|
EglCheck();
|
2021-12-29 12:08:12 +01:00
|
|
|
|
|
|
|
assert(eglDisplay != NULL);
|
|
|
|
// return;
|
2019-12-10 10:45:22 +01:00
|
|
|
|
|
|
|
drmModeAtomicReqPtr ModeReq;
|
|
|
|
const uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
|
|
|
|
uint32_t modeID = 0;
|
|
|
|
|
|
|
|
if (drmModeCreatePropertyBlob(render->fd_drm, &render->mode, sizeof(render->mode), &modeID) != 0) {
|
|
|
|
fprintf(stderr, "Failed to create mode property.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!(ModeReq = drmModeAtomicAlloc())) {
|
|
|
|
fprintf(stderr, "cannot allocate atomic request (%d): %m\n", errno);
|
|
|
|
return;
|
|
|
|
}
|
2021-12-29 12:08:12 +01:00
|
|
|
printf("set CRTC %d of Connector %d aktiv\n", render->crtc_id, render->connector_id);
|
|
|
|
SetPropertyRequest(ModeReq, render->fd_drm, render->crtc_id, DRM_MODE_OBJECT_CRTC, "MODE_ID", modeID);
|
|
|
|
SetPropertyRequest(ModeReq, render->fd_drm, render->connector_id, DRM_MODE_OBJECT_CONNECTOR, "CRTC_ID",
|
|
|
|
render->crtc_id);
|
|
|
|
SetPropertyRequest(ModeReq, render->fd_drm, render->crtc_id, DRM_MODE_OBJECT_CRTC, "ACTIVE", 1);
|
2020-04-10 16:17:23 +02:00
|
|
|
|
2019-12-10 10:45:22 +01:00
|
|
|
if (drmModeAtomicCommit(render->fd_drm, ModeReq, flags, NULL) != 0)
|
|
|
|
fprintf(stderr, "cannot set atomic mode (%d): %m\n", errno);
|
2020-04-10 16:17:23 +02:00
|
|
|
|
2019-12-17 12:15:35 +01:00
|
|
|
if (drmModeDestroyPropertyBlob(render->fd_drm, modeID) != 0)
|
2020-01-07 22:22:07 +01:00
|
|
|
fprintf(stderr, "cannot destroy property blob (%d): %m\n", errno);
|
2020-04-10 16:17:23 +02:00
|
|
|
|
2019-12-10 10:45:22 +01:00
|
|
|
drmModeAtomicFree(ModeReq);
|
|
|
|
}
|
|
|
|
|
2021-12-29 12:08:12 +01:00
|
|
|
void get_drm_aspect(int *num, int *den) {
|
2020-04-13 18:04:57 +02:00
|
|
|
*num = VideoWindowWidth;
|
|
|
|
*den = VideoWindowHeight;
|
2019-12-12 11:31:40 +01:00
|
|
|
}
|
2019-12-10 10:45:22 +01:00
|
|
|
|
2021-12-29 12:08:12 +01:00
|
|
|
struct gbm_bo *bo = NULL, *next_bo = NULL;
|
2019-12-10 10:45:22 +01:00
|
|
|
struct drm_fb *fb;
|
|
|
|
static int m_need_modeset = 0;
|
2021-12-29 12:08:12 +01:00
|
|
|
static int old_color = -1, old_trc = -1;
|
2019-12-10 10:45:22 +01:00
|
|
|
|
|
|
|
void InitBo(int bpp) {
|
|
|
|
// create the GBM and EGL surface
|
2021-12-29 12:08:12 +01:00
|
|
|
|
2019-12-10 10:45:22 +01:00
|
|
|
render->bpp = bpp;
|
2021-12-29 12:08:12 +01:00
|
|
|
gbm.surface = gbm_surface_create(gbm.dev, VideoWindowWidth, VideoWindowHeight,
|
|
|
|
bpp == 10 ? GBM_FORMAT_XRGB2101010 : GBM_FORMAT_ARGB8888,
|
|
|
|
GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
|
2019-12-10 10:45:22 +01:00
|
|
|
assert(gbm.surface != NULL);
|
2021-12-29 12:08:12 +01:00
|
|
|
eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, gbm.surface, NULL);
|
2019-12-10 10:45:22 +01:00
|
|
|
assert(eglSurface != NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct gbm_bo *previous_bo = NULL;
|
|
|
|
static uint32_t previous_fb;
|
2021-03-16 09:40:08 +01:00
|
|
|
static int has_modeset = 0;
|
2019-12-10 10:45:22 +01:00
|
|
|
|
2021-12-29 12:08:12 +01:00
|
|
|
static void drm_swap_buffers() {
|
2020-04-10 16:17:23 +02:00
|
|
|
|
2019-12-10 10:45:22 +01:00
|
|
|
uint32_t fb;
|
2020-04-10 16:17:23 +02:00
|
|
|
|
2021-12-29 12:08:12 +01:00
|
|
|
eglSwapBuffers(eglDisplay, eglSurface);
|
|
|
|
struct gbm_bo *bo = gbm_surface_lock_front_buffer(gbm.surface);
|
2019-12-10 10:45:22 +01:00
|
|
|
#if 1
|
2019-12-17 12:15:35 +01:00
|
|
|
if (bo == NULL)
|
2021-12-29 12:08:12 +01:00
|
|
|
bo = gbm_surface_lock_front_buffer(gbm.surface);
|
2019-12-10 10:45:22 +01:00
|
|
|
#endif
|
2021-12-29 12:08:12 +01:00
|
|
|
assert(bo != NULL);
|
|
|
|
uint32_t handle = gbm_bo_get_handle(bo).u32;
|
|
|
|
uint32_t pitch = gbm_bo_get_stride(bo);
|
2019-12-10 10:45:22 +01:00
|
|
|
|
2021-12-29 12:08:12 +01:00
|
|
|
drmModeAddFB(render->fd_drm, VideoWindowWidth, VideoWindowHeight, render->bpp == 10 ? 30 : 24, 32, pitch, handle,
|
|
|
|
&fb);
|
|
|
|
// drmModeSetCrtc (render->fd_drm, render->crtc_id, fb, 0, 0, &render->connector_id, 1, &render->mode);
|
2020-04-10 16:17:23 +02:00
|
|
|
|
2019-12-17 12:15:35 +01:00
|
|
|
if (m_need_modeset) {
|
|
|
|
drmModeAtomicReqPtr ModeReq;
|
|
|
|
const uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
|
|
|
|
uint32_t modeID = 0;
|
|
|
|
|
|
|
|
if (drmModeCreatePropertyBlob(render->fd_drm, &render->mode, sizeof(render->mode), &modeID) != 0) {
|
|
|
|
fprintf(stderr, "Failed to create mode property.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!(ModeReq = drmModeAtomicAlloc())) {
|
|
|
|
fprintf(stderr, "cannot allocate atomic request (%d): %m\n", errno);
|
|
|
|
return;
|
|
|
|
}
|
2020-04-10 16:17:23 +02:00
|
|
|
|
|
|
|
// Need to disable the CRTC in order to submit the HDR data....
|
2021-12-29 12:08:12 +01:00
|
|
|
SetPropertyRequest(ModeReq, render->fd_drm, render->crtc_id, DRM_MODE_OBJECT_CRTC, "ACTIVE", 0);
|
2019-12-17 12:15:35 +01:00
|
|
|
if (drmModeAtomicCommit(render->fd_drm, ModeReq, flags, NULL) != 0)
|
|
|
|
fprintf(stderr, "cannot set atomic mode (%d): %m\n", errno);
|
2021-12-29 12:08:12 +01:00
|
|
|
|
|
|
|
SetPropertyRequest(ModeReq, render->fd_drm, render->connector_id, DRM_MODE_OBJECT_CONNECTOR, "Colorspace",
|
|
|
|
old_color == AVCOL_PRI_BT2020 ? 9 : 2);
|
|
|
|
SetPropertyRequest(ModeReq, render->fd_drm, render->video_plane, DRM_MODE_OBJECT_PLANE, "COLOR_ENCODING",
|
|
|
|
old_color == AVCOL_PRI_BT2020 ? 2 : 1);
|
|
|
|
SetPropertyRequest(ModeReq, render->fd_drm, render->video_plane, DRM_MODE_OBJECT_PLANE, "COLOR_RANGE", 0);
|
|
|
|
SetPropertyRequest(ModeReq, render->fd_drm, render->crtc_id, DRM_MODE_OBJECT_CRTC, "MODE_ID", modeID);
|
|
|
|
SetPropertyRequest(ModeReq, render->fd_drm, render->connector_id, DRM_MODE_OBJECT_CONNECTOR, "CRTC_ID",
|
|
|
|
render->crtc_id);
|
|
|
|
SetPropertyRequest(ModeReq, render->fd_drm, render->crtc_id, DRM_MODE_OBJECT_CRTC, "ACTIVE", 1);
|
2020-04-10 16:17:23 +02:00
|
|
|
|
2019-12-17 12:15:35 +01:00
|
|
|
if (drmModeAtomicCommit(render->fd_drm, ModeReq, flags, NULL) != 0)
|
2021-03-16 09:40:08 +01:00
|
|
|
fprintf(stderr, "cannot set atomic mode modeset 2 (%d): %m\n", errno);
|
2019-12-17 12:15:35 +01:00
|
|
|
|
|
|
|
if (drmModeDestroyPropertyBlob(render->fd_drm, modeID) != 0)
|
|
|
|
fprintf(stderr, "cannot destroy prperty blob (%d): %m\n", errno);
|
|
|
|
|
|
|
|
drmModeAtomicFree(ModeReq);
|
|
|
|
m_need_modeset = 0;
|
2021-03-16 09:40:08 +01:00
|
|
|
has_modeset = 1;
|
2019-12-17 12:15:35 +01:00
|
|
|
}
|
2021-12-29 12:08:12 +01:00
|
|
|
drmModeSetCrtc(render->fd_drm, render->crtc_id, fb, 0, 0, &render->connector_id, 1, &render->mode);
|
2020-04-10 16:17:23 +02:00
|
|
|
|
2019-12-17 12:15:35 +01:00
|
|
|
if (previous_bo) {
|
2021-12-29 12:08:12 +01:00
|
|
|
drmModeRmFB(render->fd_drm, previous_fb);
|
|
|
|
gbm_surface_release_buffer(gbm.surface, previous_bo);
|
2019-12-10 10:45:22 +01:00
|
|
|
}
|
|
|
|
previous_bo = bo;
|
|
|
|
previous_fb = fb;
|
|
|
|
}
|
|
|
|
|
2021-12-29 12:08:12 +01:00
|
|
|
static void drm_clean_up() {
|
2019-12-10 10:45:22 +01:00
|
|
|
// set the previous crtc
|
2020-01-07 22:22:07 +01:00
|
|
|
|
2019-12-17 12:15:35 +01:00
|
|
|
if (!render)
|
|
|
|
return;
|
2021-12-29 12:08:12 +01:00
|
|
|
Debug(3, "drm clean up\n");
|
2020-01-07 22:22:07 +01:00
|
|
|
|
2021-03-16 09:40:08 +01:00
|
|
|
if (previous_bo) {
|
2021-12-29 12:08:12 +01:00
|
|
|
drmModeRmFB(render->fd_drm, previous_fb);
|
|
|
|
gbm_surface_release_buffer(gbm.surface, previous_bo);
|
2019-12-10 10:45:22 +01:00
|
|
|
}
|
2020-04-10 16:17:23 +02:00
|
|
|
|
2021-12-29 12:08:12 +01:00
|
|
|
drmModeSetCrtc(render->fd_drm, render->saved_crtc->crtc_id, render->saved_crtc->buffer_id, render->saved_crtc->x,
|
|
|
|
render->saved_crtc->y, &render->connector_id, 1, &render->saved_crtc->mode);
|
|
|
|
drmModeFreeCrtc(render->saved_crtc);
|
|
|
|
|
2021-03-16 09:40:08 +01:00
|
|
|
if (has_modeset) {
|
|
|
|
drmModeAtomicReqPtr ModeReq;
|
|
|
|
const uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
|
|
|
|
uint32_t modeID = 0;
|
2020-04-10 16:17:23 +02:00
|
|
|
|
2021-03-16 09:40:08 +01:00
|
|
|
if (drmModeCreatePropertyBlob(render->fd_drm, &render->mode, sizeof(render->mode), &modeID) != 0) {
|
|
|
|
fprintf(stderr, "Failed to create mode property.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!(ModeReq = drmModeAtomicAlloc())) {
|
|
|
|
fprintf(stderr, "cannot allocate atomic request (%d): %m\n", errno);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Need to disable the CRTC in order to submit the HDR data....
|
2021-12-29 12:08:12 +01:00
|
|
|
SetPropertyRequest(ModeReq, render->fd_drm, render->crtc_id, DRM_MODE_OBJECT_CRTC, "ACTIVE", 0);
|
2021-03-16 09:40:08 +01:00
|
|
|
if (drmModeAtomicCommit(render->fd_drm, ModeReq, flags, NULL) != 0)
|
|
|
|
fprintf(stderr, "cannot set atomic mode (%d): %m\n", errno);
|
2021-12-29 12:08:12 +01:00
|
|
|
|
|
|
|
SetPropertyRequest(ModeReq, render->fd_drm, render->connector_id, DRM_MODE_OBJECT_CONNECTOR,
|
|
|
|
"HDR_OUTPUT_METADATA", 0);
|
|
|
|
SetPropertyRequest(ModeReq, render->fd_drm, render->connector_id, DRM_MODE_OBJECT_CONNECTOR, "Colorspace", 2);
|
|
|
|
SetPropertyRequest(ModeReq, render->fd_drm, render->video_plane, DRM_MODE_OBJECT_PLANE, "COLOR_ENCODING", 1);
|
|
|
|
SetPropertyRequest(ModeReq, render->fd_drm, render->video_plane, DRM_MODE_OBJECT_PLANE, "COLOR_RANGE", 1);
|
|
|
|
SetPropertyRequest(ModeReq, render->fd_drm, render->crtc_id, DRM_MODE_OBJECT_CRTC, "MODE_ID", modeID);
|
|
|
|
SetPropertyRequest(ModeReq, render->fd_drm, render->connector_id, DRM_MODE_OBJECT_CONNECTOR, "CRTC_ID",
|
|
|
|
render->crtc_id);
|
|
|
|
SetPropertyRequest(ModeReq, render->fd_drm, render->crtc_id, DRM_MODE_OBJECT_CRTC, "ACTIVE", 1);
|
2021-03-16 09:40:08 +01:00
|
|
|
|
|
|
|
if (drmModeAtomicCommit(render->fd_drm, ModeReq, flags, NULL) != 0)
|
|
|
|
fprintf(stderr, "cannot set atomic mode (%d): %m\n", errno);
|
|
|
|
|
|
|
|
if (drmModeDestroyPropertyBlob(render->fd_drm, modeID) != 0)
|
|
|
|
fprintf(stderr, "cannot destroy prperty blob (%d): %m\n", errno);
|
|
|
|
|
|
|
|
drmModeAtomicFree(ModeReq);
|
|
|
|
has_modeset = 0;
|
|
|
|
}
|
2021-12-29 12:08:12 +01:00
|
|
|
|
2020-01-07 22:22:07 +01:00
|
|
|
if (render->hdr_blob_id)
|
|
|
|
drmModeDestroyPropertyBlob(render->fd_drm, render->hdr_blob_id);
|
2021-03-16 09:40:08 +01:00
|
|
|
render->hdr_blob_id = 0;
|
2020-04-10 16:17:23 +02:00
|
|
|
|
2021-12-29 12:08:12 +01:00
|
|
|
eglDestroySurface(eglDisplay, eglSurface);
|
2021-03-16 09:40:08 +01:00
|
|
|
EglCheck();
|
2021-12-29 12:08:12 +01:00
|
|
|
gbm_surface_destroy(gbm.surface);
|
|
|
|
eglDestroyContext(eglDisplay, eglContext);
|
2021-03-16 09:40:08 +01:00
|
|
|
EglCheck();
|
2021-12-29 12:08:12 +01:00
|
|
|
eglDestroyContext(eglDisplay, eglSharedContext);
|
2021-03-16 09:40:08 +01:00
|
|
|
EglCheck();
|
|
|
|
eglSharedContext = NULL;
|
2020-01-07 22:22:07 +01:00
|
|
|
|
2021-12-29 12:08:12 +01:00
|
|
|
eglTerminate(eglDisplay);
|
2021-03-16 09:40:08 +01:00
|
|
|
EglCheck();
|
2020-04-10 16:17:23 +02:00
|
|
|
|
2021-12-29 12:08:12 +01:00
|
|
|
gbm_device_destroy(gbm.dev);
|
2021-03-16 09:40:08 +01:00
|
|
|
drmDropMaster(render->fd_drm);
|
2021-12-29 12:08:12 +01:00
|
|
|
close(render->fd_drm);
|
2021-03-16 09:40:08 +01:00
|
|
|
eglDisplay = NULL;
|
|
|
|
free(render);
|
2022-05-24 00:09:55 +02:00
|
|
|
}
|