From b1d111b5f796dd2bfb409106878a6f2a58205b11 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Thu, 31 Aug 2023 21:18:05 -0500 Subject: [PATCH] Only use atomic API for HDR streams on RK backend --- src/video/rk.c | 133 +++++++++++++++++++++++++++++-------------------- 1 file changed, 79 insertions(+), 54 deletions(-) diff --git a/src/video/rk.c b/src/video/rk.c index b57278b..ac6ec03 100644 --- a/src/video/rk.c +++ b/src/video/rk.c @@ -106,6 +106,7 @@ int crtc_height; RK_U32 frm_width; RK_U32 frm_height; int fb_x, fb_y, fb_width, fb_height; +bool atomic; uint8_t last_colorspace = 0xFF; bool last_hdr_state = false; @@ -138,21 +139,23 @@ struct { uint32_t handle; } frame_to_drm[MAX_FRAMES]; -int set_atomic_property(drmModeAtomicReq *request, uint32_t id, drmModePropertyPtr *props, char *name, uint64_t value) { - while (*props) { - if (!strcasecmp(name, (*props)->name)) { - return drmModeAtomicAddProperty(request, id, (*props)->prop_id, value); - } - props++; - } +int set_property(uint32_t id, uint32_t type, drmModePropertyPtr *props, char *name, uint64_t value) { + while (*props) { + if (!strcasecmp(name, (*props)->name)) { + if (atomic) + return drmModeAtomicAddProperty(drm_request, id, (*props)->prop_id, value); + else + return drmModeObjectSetProperty(fd, id, type, (*props)->prop_id, value); + } + props++; + } - return -EINVAL; + fprintf(stderr, "Property '%s' not found\n", name); + return -EINVAL; } void *display_thread(void *param) { - int ret; - while (!frm_eos) { int _fb_id; @@ -173,28 +176,16 @@ void *display_thread(void *param) { ret = pthread_mutex_unlock(&mutex); assert(!ret); - uint32_t v4l2_colorspace; - switch (last_colorspace) { - default: - fprintf(stderr, "Unknown frame colorspace: %d\n", last_colorspace); - /* fall-through */ - case COLORSPACE_REC_601: - v4l2_colorspace = V4L2_COLORSPACE_SMPTE170M; - break; - case COLORSPACE_REC_709: - v4l2_colorspace = V4L2_COLORSPACE_REC709; - break; - case COLORSPACE_REC_2020: - v4l2_colorspace = V4L2_COLORSPACE_BT2020; - break; + if (atomic) { + // We may need to modeset to apply colorspace changes when toggling HDR + set_property(plane_id, DRM_MODE_OBJECT_PLANE, plane_props, "FB_ID", _fb_id); + ret = drmModeAtomicCommit(fd, drm_request, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL); + } else { + ret = drmModeSetPlane(fd, plane_id, crtc_id, _fb_id, 0, + fb_x, fb_y, fb_width, fb_height, + 0, 0, frm_width << 16, frm_height << 16); } - set_atomic_property(drm_request, plane_id, plane_props, "COLOR_SPACE", v4l2_colorspace); - set_atomic_property(drm_request, plane_id, plane_props, "EOTF", last_hdr_state ? 2 : 0); // PQ or SDR - set_atomic_property(drm_request, plane_id, plane_props, "FB_ID", _fb_id); - - // We may need to modeset to apply colorspace changes when toggling HDR - ret = drmModeAtomicCommit(fd, drm_request, DRM_MODE_ATOMIC_NONBLOCK | DRM_MODE_ATOMIC_ALLOW_MODESET, NULL); - assert(!ret || errno == EBUSY); + assert(!ret); } return NULL; @@ -297,20 +288,22 @@ void *frame_thread(void *param) { ret = mpi_api->control(mpi_ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL); // Set atomic properties for the plane prior to the first commit - set_atomic_property(drm_request, plane_id, plane_props, "CRTC_ID", crtc_id); - set_atomic_property(drm_request, plane_id, plane_props, "SRC_X", 0 << 16); - set_atomic_property(drm_request, plane_id, plane_props, "SRC_Y", 0 << 16); - set_atomic_property(drm_request, plane_id, plane_props, "SRC_W", frm_width << 16); - set_atomic_property(drm_request, plane_id, plane_props, "SRC_H", frm_height << 16); - set_atomic_property(drm_request, plane_id, plane_props, "CRTC_X", fb_x); - set_atomic_property(drm_request, plane_id, plane_props, "CRTC_Y", fb_y); - set_atomic_property(drm_request, plane_id, plane_props, "CRTC_W", fb_width); - set_atomic_property(drm_request, plane_id, plane_props, "CRTC_H", fb_height); - set_atomic_property(drm_request, plane_id, plane_props, "ZPOS", 0); + if (atomic) { + set_property(plane_id, DRM_MODE_OBJECT_PLANE, plane_props, "CRTC_ID", crtc_id); + set_property(plane_id, DRM_MODE_OBJECT_PLANE, plane_props, "SRC_X", 0 << 16); + set_property(plane_id, DRM_MODE_OBJECT_PLANE, plane_props, "SRC_Y", 0 << 16); + set_property(plane_id, DRM_MODE_OBJECT_PLANE, plane_props, "SRC_W", frm_width << 16); + set_property(plane_id, DRM_MODE_OBJECT_PLANE, plane_props, "SRC_H", frm_height << 16); + set_property(plane_id, DRM_MODE_OBJECT_PLANE, plane_props, "CRTC_X", fb_x); + set_property(plane_id, DRM_MODE_OBJECT_PLANE, plane_props, "CRTC_Y", fb_y); + set_property(plane_id, DRM_MODE_OBJECT_PLANE, plane_props, "CRTC_W", fb_width); + set_property(plane_id, DRM_MODE_OBJECT_PLANE, plane_props, "CRTC_H", fb_height); + set_property(plane_id, DRM_MODE_OBJECT_PLANE, plane_props, "ZPOS", 0); + } - // Set atomic properties on the connector - set_atomic_property(drm_request, conn_id, conn_props, "allm_enable", 1); // HDMI ALLM (Game Mode) - set_atomic_property(drm_request, conn_id, conn_props, "Colorspace", last_hdr_state ? DRM_MODE_COLORIMETRY_BT2020_RGB : DRM_MODE_COLORIMETRY_DEFAULT); + // Set properties on the connector + set_property(conn_id, DRM_MODE_OBJECT_CONNECTOR, conn_props, "allm_enable", 1); // HDMI ALLM (Game Mode) + set_property(conn_id, DRM_MODE_OBJECT_CONNECTOR, conn_props, "Colorspace", last_hdr_state ? DRM_MODE_COLORIMETRY_BT2020_RGB : DRM_MODE_COLORIMETRY_DEFAULT); } else { // regular frame received @@ -370,6 +363,11 @@ int rk_setup(int videoFormat, int width, int height, int redrawRate, void* conte return -1; } + // We need atomic plane properties for HDR, but atomic seems to perform quite bad + // on RK3588 for some reason. The performance of commits seems to go down the longer + // the stream runs. We'll use the legacy API for non-HDR streams as a workaround. + atomic = !!(videoFormat & VIDEO_FORMAT_MASK_10BIT); + MppCodingType mpp_type = (MppCodingType)format; ret = mpp_check_support_format(MPP_CTX_DEC, mpp_type); if (ret) { @@ -444,10 +442,12 @@ int rk_setup(int videoFormat, int width, int height, int redrawRate, void* conte ret = drmSetClientCap(fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); assert(!ret); - ret = drmSetClientCap(fd, DRM_CLIENT_CAP_ATOMIC, 1); - assert(!ret); - drm_request = drmModeAtomicAlloc(); - assert(drm_request); + if (atomic) { + ret = drmSetClientCap(fd, DRM_CLIENT_CAP_ATOMIC, 1); + assert(!ret); + drm_request = drmModeAtomicAlloc(); + assert(drm_request); + } plane_resources = drmModeGetPlaneResources(fd); assert(plane_resources); @@ -598,18 +598,21 @@ void rk_cleanup() { free(pkt_buf); // Undo the connector-wide changes we performed - drmModeAtomicSetCursor(drm_request, 0); - set_atomic_property(drm_request, conn_id, conn_props, "HDR_OUTPUT_METADATA", 0); - set_atomic_property(drm_request, conn_id, conn_props, "allm_enable", 0); - set_atomic_property(drm_request, conn_id, conn_props, "Colorspace", DRM_MODE_COLORIMETRY_DEFAULT); - drmModeAtomicCommit(fd, drm_request, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL); + if (atomic) + drmModeAtomicSetCursor(drm_request, 0); + set_property(conn_id, DRM_MODE_OBJECT_CONNECTOR, conn_props, "HDR_OUTPUT_METADATA", 0); + set_property(conn_id, DRM_MODE_OBJECT_CONNECTOR, conn_props, "allm_enable", 0); + set_property(conn_id, DRM_MODE_OBJECT_CONNECTOR, conn_props, "Colorspace", DRM_MODE_COLORIMETRY_DEFAULT); + if (atomic) + drmModeAtomicCommit(fd, drm_request, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL); if (hdr_metadata_blob_id) { drmModeDestroyPropertyBlob(fd, hdr_metadata_blob_id); hdr_metadata_blob_id = 0; } - drmModeAtomicFree(drm_request); + if (atomic) + drmModeAtomicFree(drm_request); drmModeFreePlane(ovr); drmModeFreePlaneResources(plane_resources); drmModeFreeEncoder(encoder); @@ -689,6 +692,28 @@ int rk_submit_decode_unit(PDECODE_UNIT decodeUnit) { } else { fprintf(stderr, "HDR_OUTPUT_METADATA property is not supported by your display/kernel. Do you have an HDR display connected?\n"); } + + // Adjust plane EOTF property + set_property(plane_id, DRM_MODE_OBJECT_PLANE, plane_props, "EOTF", decodeUnit->hdrActive ? 2 : 0); // PQ or SDR + } + + if (last_colorspace != decodeUnit->colorspace) { + uint32_t v4l2_colorspace; + switch (decodeUnit->colorspace) { + default: + fprintf(stderr, "Unknown frame colorspace: %d\n", decodeUnit->colorspace); + /* fall-through */ + case COLORSPACE_REC_601: + v4l2_colorspace = V4L2_COLORSPACE_SMPTE170M; + break; + case COLORSPACE_REC_709: + v4l2_colorspace = V4L2_COLORSPACE_REC709; + break; + case COLORSPACE_REC_2020: + v4l2_colorspace = V4L2_COLORSPACE_BT2020; + break; + } + set_property(plane_id, DRM_MODE_OBJECT_PLANE, plane_props, "COLOR_SPACE", v4l2_colorspace); } last_colorspace = decodeUnit->colorspace;