Handle the FB_ID and LUT_3D_FORMAT properties in the colorop atomic get/set paths, and report LUT_3D_FORMATS (the immutable formats blob) on get. Setting FB_ID looks up the framebuffer and swaps the reference into the colorop state (taking the new reference, dropping the old), mirroring the plane FB_ID handling.
RMFB, and closing the DRM file that owns a framebuffer, disable the planes that scan it out. Without further handling a colorop using the framebuffer would keep it alive and the hardware would keep fetching from it. Make atomic_remove_fb() also bypass every colorop using the framebuffer and clear its FB_ID, flagging the plane's color management as changed. Bypassing keeps the plane visible without the LUT, which is less disruptive than disabling it. Document this in the RMFB and CLOSEFB uAPI. Also print the selected format index and framebuffer id for a DRM_COLOROP_3D_LUT_DMA colorop in the atomic state dump. Signed-off-by: Harry Wentland <[email protected]> --- drivers/gpu/drm/drm_atomic.c | 4 +++ drivers/gpu/drm/drm_atomic_uapi.c | 24 +++++++++++++++++ drivers/gpu/drm/drm_framebuffer.c | 45 ++++++++++++++++++++++++++++++- include/uapi/drm/drm.h | 7 ++--- 4 files changed, 76 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 9bb761eda59f..158f41eae76f 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -939,6 +939,10 @@ static void drm_atomic_colorop_print_state(struct drm_printer *p, drm_printf_indent(p, 1, "fixed_matrix_type=%s\n", drm_get_colorop_fixed_matrix_type_name(state->fixed_matrix_type)); break; + case DRM_COLOROP_3D_LUT_DMA: + drm_printf_indent(p, 1, "lut_3d_format=%u\n", state->lut_3d_format); + drm_printf_indent(p, 1, "fb=%u\n", state->fb ? state->fb->base.id : 0); + break; default: break; } diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index aca0edb42a5a..05a2a3b46351 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -791,6 +791,24 @@ static int drm_atomic_colorop_set_property(struct drm_colorop *colorop, state->fixed_matrix_type = val; *replaced = true; } + } else if (property == colorop->lut_3d_format_property) { + if (state->lut_3d_format != val) { + state->lut_3d_format = val; + *replaced = true; + } + } else if (property == colorop->fb_property) { + struct drm_framebuffer *fb = NULL; + + if (val) { + fb = drm_framebuffer_lookup(colorop->dev, file_priv, val); + if (!fb) + return -EINVAL; + } + if (state->fb != fb) + *replaced = true; + drm_framebuffer_assign(&state->fb, fb); + if (fb) + drm_framebuffer_put(fb); } else { drm_dbg_atomic(colorop->dev, "[COLOROP:%d:%d] unknown property [PROP:%d:%s]\n", @@ -825,6 +843,12 @@ drm_atomic_colorop_get_property(struct drm_colorop *colorop, *val = (state->data) ? state->data->base.id : 0; else if (property == colorop->fixed_matrix_type_property) *val = state->fixed_matrix_type; + else if (property == colorop->lut_3d_formats_property) + *val = colorop->lut_3d_formats_blob ? colorop->lut_3d_formats_blob->base.id : 0; + else if (property == colorop->lut_3d_format_property) + *val = state->lut_3d_format; + else if (property == colorop->fb_property) + *val = (state->fb) ? state->fb->base.id : 0; else return -EINVAL; diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index d32aceb6ca9b..05cce02238bc 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -26,6 +26,7 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_uapi.h> #include <drm/drm_auth.h> +#include <drm/drm_colorop.h> #include <drm/drm_debugfs.h> #include <drm/drm_drv.h> #include <drm/drm_file.h> @@ -1002,10 +1003,12 @@ static int atomic_remove_fb(struct drm_framebuffer *fb) struct drm_device *dev = fb->dev; struct drm_atomic_commit *state; struct drm_plane *plane; + struct drm_colorop *colorop; struct drm_connector *conn __maybe_unused; struct drm_connector_state *conn_state; int i, ret; unsigned plane_mask; + bool colorops_changed; bool disable_crtcs = false; retry_disable: @@ -1020,6 +1023,7 @@ static int atomic_remove_fb(struct drm_framebuffer *fb) retry: plane_mask = 0; + colorops_changed = false; ret = drm_modeset_lock_all_ctx(dev, &ctx); if (ret) goto unlock; @@ -1068,6 +1072,45 @@ static int atomic_remove_fb(struct drm_framebuffer *fb) plane_mask |= drm_plane_mask(plane); } + /* + * Colorops that fetch data from a framebuffer, such as a DMA 3D LUT, + * are bypassed rather than disabling their plane. Such colorops are + * required to support bypass. + */ + drm_for_each_colorop(colorop, dev) { + struct drm_colorop_state *colorop_state; + struct drm_plane_state *plane_state; + + if (!colorop->state || colorop->state->fb != fb) + continue; + + if (drm_WARN_ON(dev, !colorop->bypass_property)) { + ret = -EINVAL; + goto unlock; + } + + drm_dbg_kms(dev, + "Bypassing [COLOROP:%d] because [FB:%d] is removed\n", + colorop->base.id, fb->base.id); + + colorop_state = drm_atomic_get_colorop_state(state, colorop); + if (IS_ERR(colorop_state)) { + ret = PTR_ERR(colorop_state); + goto unlock; + } + + plane_state = drm_atomic_get_plane_state(state, colorop->plane); + if (IS_ERR(plane_state)) { + ret = PTR_ERR(plane_state); + goto unlock; + } + + drm_framebuffer_assign(&colorop_state->fb, NULL); + colorop_state->bypass = true; + plane_state->color_mgmt_changed = true; + colorops_changed = true; + } + /* This list is only filled when disable_crtcs is set. */ for_each_new_connector_in_state(state, conn, conn_state, i) { ret = drm_atomic_set_crtc_for_connector(conn_state, NULL); @@ -1076,7 +1119,7 @@ static int atomic_remove_fb(struct drm_framebuffer *fb) goto unlock; } - if (plane_mask) + if (plane_mask || colorops_changed) ret = drm_atomic_commit(state); unlock: diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index bc7ef7684099..2a06e8e08dbe 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -1217,7 +1217,8 @@ extern "C" { * * Warning: removing a framebuffer currently in-use on an enabled plane will * disable that plane. The CRTC the plane is linked to may also be disabled - * (depending on driver capabilities). + * (depending on driver capabilities). Colorops using the framebuffer, such + * as a DMA 3D LUT, are bypassed instead. */ #define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xAF, unsigned int) #define DRM_IOCTL_MODE_PAGE_FLIP DRM_IOWR(0xB0, struct drm_mode_crtc_page_flip) @@ -1321,8 +1322,8 @@ extern "C" { * argument is a framebuffer object ID. * * This IOCTL is similar to &DRM_IOCTL_MODE_RMFB, except it doesn't disable - * planes and CRTCs. As long as the framebuffer is used by a plane, it's kept - * alive. When the plane no longer uses the framebuffer (because the + * planes and CRTCs, or bypass colorops. As long as the framebuffer is used by + * a plane or colorop, it's kept alive. When it is no longer used (because the * framebuffer is replaced with another one, or the plane is disabled), the * framebuffer is cleaned up. * -- 2.56.0
