Don't select an overlay plane with a lower zpos than the primary plane

This commit is contained in:
Cameron Gutman 2024-06-23 17:55:27 -05:00
parent 94943d2865
commit 0f57abf6f8
2 changed files with 119 additions and 71 deletions

View File

@ -179,6 +179,24 @@ bool DrmRenderer::prepareDecoderContext(AVCodecContext* context, AVDictionary**
return true;
}
bool DrmRenderer::getPropertyByName(drmModeObjectPropertiesPtr props, const char* name, uint64_t *value) {
for (uint32_t j = 0; j < props->count_props; j++) {
drmModePropertyPtr prop = drmModeGetProperty(m_DrmFd, props->props[j]);
if (prop != nullptr) {
if (!strcmp(prop->name, name)) {
*value = props->prop_values[j];
drmModeFreeProperty(prop);
return true;
}
else {
drmModeFreeProperty(prop);
}
}
}
return false;
}
bool DrmRenderer::initialize(PDECODER_PARAMETERS params)
{
int i;
@ -433,9 +451,21 @@ bool DrmRenderer::initialize(PDECODER_PARAMETERS params)
// than just assuming it will be a certain hardcoded type like NV12 based
// on the chosen video format.
m_PlaneId = 0;
for (uint32_t i = 0; i < planeRes->count_planes && m_PlaneId == 0; i++) {
uint64_t maxZpos = 0;
for (uint32_t i = 0; i < planeRes->count_planes; i++) {
drmModePlane* plane = drmModeGetPlane(m_DrmFd, planeRes->planes[i]);
if (plane != nullptr) {
// If the plane can't be used on our CRTC, don't consider it further
if (!(plane->possible_crtcs & (1 << crtcIndex))) {
drmModeFreePlane(plane);
continue;
}
// We don't check plane->crtc_id here because we want to be able to reuse the primary plane
// that may owned by Qt and in use on a CRTC prior to us taking over DRM master. When we give
// control back to Qt, it will repopulate the plane with the FB it owns and render as normal.
// Validate that the candidate plane supports our pixel format
bool matchingFormat = false;
for (uint32_t j = 0; j < plane->count_formats && !matchingFormat; j++) {
if (m_Main10Hdr) {
@ -457,47 +487,38 @@ bool DrmRenderer::initialize(PDECODER_PARAMETERS params)
}
}
if (matchingFormat == false) {
if (!matchingFormat) {
drmModeFreePlane(plane);
continue;
}
// We don't check plane->crtc_id here because we want to be able to reuse the primary plane
// that may owned by Qt and in use on a CRTC prior to us taking over DRM master. When we give
// control back to Qt, it will repopulate the plane with the FB it owns and render as normal.
if ((plane->possible_crtcs & (1 << crtcIndex))) {
drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(m_DrmFd, planeRes->planes[i], DRM_MODE_OBJECT_PLANE);
if (props != nullptr) {
for (uint32_t j = 0; j < props->count_props; j++) {
drmModePropertyPtr prop = drmModeGetProperty(m_DrmFd, props->props[j]);
if (prop != nullptr) {
if (!strcmp(prop->name, "type") &&
(props->prop_values[j] == DRM_PLANE_TYPE_PRIMARY || props->prop_values[j] == DRM_PLANE_TYPE_OVERLAY)) {
m_PlaneId = plane->plane_id;
}
if (!strcmp(prop->name, "COLOR_ENCODING")) {
m_ColorEncodingProp = prop;
}
else if (!strcmp(prop->name, "COLOR_RANGE")) {
m_ColorRangeProp = prop;
}
else {
drmModeFreeProperty(prop);
}
}
}
drmModeFreeObjectProperties(props);
drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(m_DrmFd, planeRes->planes[i], DRM_MODE_OBJECT_PLANE);
if (props != nullptr) {
// Only consider primary and overlay planes as valid render targets
uint64_t type;
if (!getPropertyByName(props, "type", &type) || (type != DRM_PLANE_TYPE_PRIMARY && type != DRM_PLANE_TYPE_OVERLAY)) {
drmModeFreePlane(plane);
continue;
}
}
// Store the plane details for use during render format testing
if (m_PlaneId != 0) {
m_Plane = plane;
}
else {
drmModeFreePlane(plane);
// If this is a higher Z position than the last candidate plane,
// let's prefer this one over the previous one. Note: zpos is not
// a required property, but if any plane has it, all planes must.
uint64_t zPos = 0;
if (!getPropertyByName(props, "zpos", &zPos) || !m_Plane || zPos > maxZpos) {
m_PlaneId = plane->plane_id;
maxZpos = zPos;
if (m_Plane) {
drmModeFreePlane(m_Plane);
}
m_Plane = plane;
}
else {
drmModeFreePlane(plane);
}
drmModeFreeObjectProperties(props);
}
}
}
@ -506,51 +527,77 @@ bool DrmRenderer::initialize(PDECODER_PARAMETERS params)
if (m_PlaneId == 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Failed to find suitable overlay plane!");
"Failed to find suitable primary/overlay plane!");
return DIRECT_RENDERING_INIT_FAILED;
}
drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(m_DrmFd, m_ConnectorId, DRM_MODE_OBJECT_CONNECTOR);
if (props != nullptr) {
for (uint32_t j = 0; j < props->count_props; j++) {
drmModePropertyPtr prop = drmModeGetProperty(m_DrmFd, props->props[j]);
if (prop != nullptr) {
if (!strcmp(prop->name, "HDR_OUTPUT_METADATA")) {
m_HdrOutputMetadataProp = prop;
}
else if (!strcmp(prop->name, "Colorspace")) {
m_ColorspaceProp = prop;
}
else if (!strcmp(prop->name, "max bpc") && m_Main10Hdr) {
if (drmModeObjectSetProperty(m_DrmFd, m_ConnectorId, DRM_MODE_OBJECT_CONNECTOR, prop->prop_id, 16) == 0) {
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Enabled 48-bit HDMI Deep Color");
// Populate plane properties
{
drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(m_DrmFd, m_PlaneId, DRM_MODE_OBJECT_PLANE);
if (props != nullptr) {
for (uint32_t j = 0; j < props->count_props; j++) {
drmModePropertyPtr prop = drmModeGetProperty(m_DrmFd, props->props[j]);
if (prop != nullptr) {
if (!strcmp(prop->name, "COLOR_ENCODING")) {
m_ColorEncodingProp = prop;
}
else if (drmModeObjectSetProperty(m_DrmFd, m_ConnectorId, DRM_MODE_OBJECT_CONNECTOR, prop->prop_id, 12) == 0) {
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Enabled 36-bit HDMI Deep Color");
}
else if (drmModeObjectSetProperty(m_DrmFd, m_ConnectorId, DRM_MODE_OBJECT_CONNECTOR, prop->prop_id, 10) == 0) {
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Enabled 30-bit HDMI Deep Color");
else if (!strcmp(prop->name, "COLOR_RANGE")) {
m_ColorRangeProp = prop;
}
else {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"drmModeObjectSetProperty(%s) failed: %d",
prop->name,
errno);
// Non-fatal
drmModeFreeProperty(prop);
}
drmModeFreeProperty(prop);
}
else {
drmModeFreeProperty(prop);
}
}
}
drmModeFreeObjectProperties(props);
drmModeFreeObjectProperties(props);
}
}
// Populate connector properties
{
drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(m_DrmFd, m_ConnectorId, DRM_MODE_OBJECT_CONNECTOR);
if (props != nullptr) {
for (uint32_t j = 0; j < props->count_props; j++) {
drmModePropertyPtr prop = drmModeGetProperty(m_DrmFd, props->props[j]);
if (prop != nullptr) {
if (!strcmp(prop->name, "HDR_OUTPUT_METADATA")) {
m_HdrOutputMetadataProp = prop;
}
else if (!strcmp(prop->name, "Colorspace")) {
m_ColorspaceProp = prop;
}
else if (!strcmp(prop->name, "max bpc") && m_Main10Hdr) {
if (drmModeObjectSetProperty(m_DrmFd, m_ConnectorId, DRM_MODE_OBJECT_CONNECTOR, prop->prop_id, 16) == 0) {
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Enabled 48-bit HDMI Deep Color");
}
else if (drmModeObjectSetProperty(m_DrmFd, m_ConnectorId, DRM_MODE_OBJECT_CONNECTOR, prop->prop_id, 12) == 0) {
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Enabled 36-bit HDMI Deep Color");
}
else if (drmModeObjectSetProperty(m_DrmFd, m_ConnectorId, DRM_MODE_OBJECT_CONNECTOR, prop->prop_id, 10) == 0) {
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Enabled 30-bit HDMI Deep Color");
}
else {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"drmModeObjectSetProperty(%s) failed: %d",
prop->name,
errno);
// Non-fatal
}
drmModeFreeProperty(prop);
}
else {
drmModeFreeProperty(prop);
}
}
}
drmModeFreeObjectProperties(props);
}
}
// If we got this far, we can do direct rendering via the DRM FD.

View File

@ -70,6 +70,7 @@ public:
#endif
private:
bool getPropertyByName(drmModeObjectPropertiesPtr props, const char* name, uint64_t *value);
const char* getDrmColorEncodingValue(AVFrame* frame);
const char* getDrmColorRangeValue(AVFrame* frame);
bool mapSoftwareFrame(AVFrame* frame, AVDRMFrameDescriptor* mappedFrame);