[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-Id: <20251223-mtk-post-blend-color-pipeline-v3-20-7d969f9a37a0@collabora.com>
Date: Tue, 23 Dec 2025 15:01:40 -0300
From: Ariel D'Alessandro <ariel.dalessandro@...labora.com>
To: Maarten Lankhorst <maarten.lankhorst@...ux.intel.com>,
Maxime Ripard <mripard@...nel.org>, Thomas Zimmermann <tzimmermann@...e.de>,
David Airlie <airlied@...il.com>, Simona Vetter <simona@...ll.ch>,
Chun-Kuang Hu <chunkuang.hu@...nel.org>,
Philipp Zabel <p.zabel@...gutronix.de>,
Matthias Brugger <matthias.bgg@...il.com>,
AngeloGioacchino Del Regno <angelogioacchino.delregno@...labora.com>,
Louis Chauvet <louis.chauvet@...tlin.com>,
Haneen Mohammed <hamohammed.sa@...il.com>,
Melissa Wen <melissa.srw@...il.com>
Cc: dri-devel@...ts.freedesktop.org, linux-kernel@...r.kernel.org,
linux-mediatek@...ts.infradead.org, linux-arm-kernel@...ts.infradead.org,
kernel@...labora.com,
Nícolas F. R. A. Prado <nfraprado@...labora.com>,
Ariel D'Alessandro <ariel.dalessandro@...labora.com>
Subject: [PATCH v3 20/21] drm/vkms: Introduce support for post-blend color
pipeline
From: "Nícolas F. R. A. Prado" <nfraprado@...labora.com>
Introduce a post-blend color pipeline with the same colorop blocks as
the pre-blend color pipeline.
Signed-off-by: Nícolas F. R. A. Prado <nfraprado@...labora.com>
Co-developed-by: Ariel D'Alessandro <ariel.dalessandro@...labora.com>
Signed-off-by: Ariel D'Alessandro <ariel.dalessandro@...labora.com>
---
drivers/gpu/drm/vkms/tests/vkms_config_test.c | 70 ++++++++++-------
drivers/gpu/drm/vkms/vkms_colorop.c | 103 ++++++++++++++++++++++++++
drivers/gpu/drm/vkms/vkms_composer.c | 5 +-
drivers/gpu/drm/vkms/vkms_config.c | 5 +-
drivers/gpu/drm/vkms/vkms_config.h | 29 +++++++-
drivers/gpu/drm/vkms/vkms_crtc.c | 6 +-
drivers/gpu/drm/vkms/vkms_drv.c | 7 +-
drivers/gpu/drm/vkms/vkms_drv.h | 6 +-
drivers/gpu/drm/vkms/vkms_output.c | 3 +-
9 files changed, 202 insertions(+), 32 deletions(-)
diff --git a/drivers/gpu/drm/vkms/tests/vkms_config_test.c b/drivers/gpu/drm/vkms/tests/vkms_config_test.c
index 1e4ea1863420f..ec1d84ae508ad 100644
--- a/drivers/gpu/drm/vkms/tests/vkms_config_test.c
+++ b/drivers/gpu/drm/vkms/tests/vkms_config_test.c
@@ -84,6 +84,7 @@ struct default_config_case {
bool enable_writeback;
bool enable_overlay;
bool enable_plane_pipeline;
+ bool enable_crtc_pipeline;
};
static void vkms_config_test_empty_config(struct kunit *test)
@@ -109,22 +110,38 @@ static void vkms_config_test_empty_config(struct kunit *test)
}
static struct default_config_case default_config_cases[] = {
- { false, false, false, false },
- { true, false, false, false },
- { true, true, false, false },
- { true, false, true, false },
- { false, true, false, false },
- { false, true, true, false },
- { false, false, true, false },
- { true, true, true, false },
- { false, false, false, true },
- { true, false, false, true },
- { true, true, false, true },
- { true, false, true, true },
- { false, true, false, true },
- { false, true, true, true },
- { false, false, true, true },
- { true, true, true, true },
+ { false, false, false, false, false },
+ { true, false, false, false, false },
+ { true, true, false, false, false },
+ { true, false, true, false, false },
+ { false, true, false, false, false },
+ { false, true, true, false, false },
+ { false, false, true, false, false },
+ { true, true, true, false, false },
+ { false, false, false, true, false },
+ { true, false, false, true, false },
+ { true, true, false, true, false },
+ { true, false, true, true, false },
+ { false, true, false, true, false },
+ { false, true, true, true, false },
+ { false, false, true, true, false },
+ { true, true, true, true, false },
+ { false, false, false, false, true },
+ { true, false, false, false, true },
+ { true, true, false, false, true },
+ { true, false, true, false, true },
+ { false, true, false, false, true },
+ { false, true, true, false, true },
+ { false, false, true, false, true },
+ { true, true, true, false, true },
+ { false, false, false, true, true },
+ { true, false, false, true, true },
+ { true, true, false, true, true },
+ { true, false, true, true, true },
+ { false, true, false, true, true },
+ { false, true, true, true, true },
+ { false, false, true, true, true },
+ { true, true, true, true, true },
};
KUNIT_ARRAY_PARAM(default_config, default_config_cases, NULL);
@@ -142,7 +159,8 @@ static void vkms_config_test_default_config(struct kunit *test)
config = vkms_config_default_create(params->enable_cursor,
params->enable_writeback,
params->enable_overlay,
- params->enable_plane_pipeline);
+ params->enable_plane_pipeline,
+ params->enable_crtc_pipeline);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config);
/* Planes */
@@ -174,6 +192,8 @@ static void vkms_config_test_default_config(struct kunit *test)
crtc_cfg = get_first_crtc(config);
KUNIT_EXPECT_EQ(test, vkms_config_crtc_get_writeback(crtc_cfg),
params->enable_writeback);
+ KUNIT_EXPECT_EQ(test, vkms_config_crtc_get_default_pipeline(crtc_cfg),
+ params->enable_crtc_pipeline);
vkms_config_for_each_plane(config, plane_cfg) {
struct vkms_config_crtc *possible_crtc;
@@ -381,7 +401,7 @@ static void vkms_config_test_invalid_plane_number(struct kunit *test)
struct vkms_config_plane *plane_cfg;
int n;
- config = vkms_config_default_create(false, false, false, false);
+ config = vkms_config_default_create(false, false, false, false, false);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config);
/* Invalid: No planes */
@@ -406,7 +426,7 @@ static void vkms_config_test_valid_plane_type(struct kunit *test)
struct vkms_config_encoder *encoder_cfg;
int err;
- config = vkms_config_default_create(false, false, false, false);
+ config = vkms_config_default_create(false, false, false, false, false);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config);
plane_cfg = get_first_plane(config);
@@ -487,7 +507,7 @@ static void vkms_config_test_valid_plane_possible_crtcs(struct kunit *test)
struct vkms_config_plane *plane_cfg;
struct vkms_config_crtc *crtc_cfg;
- config = vkms_config_default_create(false, false, false, false);
+ config = vkms_config_default_create(false, false, false, false, false);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config);
plane_cfg = get_first_plane(config);
@@ -506,7 +526,7 @@ static void vkms_config_test_invalid_crtc_number(struct kunit *test)
struct vkms_config_crtc *crtc_cfg;
int n;
- config = vkms_config_default_create(false, false, false, false);
+ config = vkms_config_default_create(false, false, false, false, false);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config);
/* Invalid: No CRTCs */
@@ -529,7 +549,7 @@ static void vkms_config_test_invalid_encoder_number(struct kunit *test)
struct vkms_config_encoder *encoder_cfg;
int n;
- config = vkms_config_default_create(false, false, false, false);
+ config = vkms_config_default_create(false, false, false, false, false);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config);
/* Invalid: No encoders */
@@ -554,7 +574,7 @@ static void vkms_config_test_valid_encoder_possible_crtcs(struct kunit *test)
struct vkms_config_encoder *encoder_cfg;
int err;
- config = vkms_config_default_create(false, false, false, false);
+ config = vkms_config_default_create(false, false, false, false, false);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config);
crtc_cfg1 = get_first_crtc(config);
@@ -600,7 +620,7 @@ static void vkms_config_test_invalid_connector_number(struct kunit *test)
struct vkms_config_connector *connector_cfg;
int n;
- config = vkms_config_default_create(false, false, false, false);
+ config = vkms_config_default_create(false, false, false, false, false);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config);
/* Invalid: No connectors */
@@ -623,7 +643,7 @@ static void vkms_config_test_valid_connector_possible_encoders(struct kunit *tes
struct vkms_config_encoder *encoder_cfg;
struct vkms_config_connector *connector_cfg;
- config = vkms_config_default_create(false, false, false, false);
+ config = vkms_config_default_create(false, false, false, false, false);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config);
encoder_cfg = get_first_encoder(config);
diff --git a/drivers/gpu/drm/vkms/vkms_colorop.c b/drivers/gpu/drm/vkms/vkms_colorop.c
index dd6120434690e..6c4a6cb186564 100644
--- a/drivers/gpu/drm/vkms/vkms_colorop.c
+++ b/drivers/gpu/drm/vkms/vkms_colorop.c
@@ -102,6 +102,91 @@ static int vkms_initialize_plane_color_pipeline(struct drm_plane *plane,
return ret;
}
+static int vkms_initialize_crtc_color_pipeline(struct drm_crtc *crtc,
+ struct drm_prop_enum_list *list)
+{
+ struct drm_colorop *ops[MAX_COLOR_PIPELINE_OPS];
+ struct drm_device *dev = crtc->dev;
+ int ret;
+ int i = 0, j = 0;
+
+ memset(ops, 0, sizeof(ops));
+
+ /* 1st op: 1d curve */
+ ops[i] = kzalloc(sizeof(*ops[i]), GFP_KERNEL);
+ if (!ops[i]) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ ret = drm_crtc_colorop_curve_1d_init(dev, ops[i], crtc, supported_tfs,
+ DRM_COLOROP_FLAG_ALLOW_BYPASS);
+ if (ret)
+ goto err_colorop_init;
+
+ list->type = ops[i]->base.id;
+ list->name = kasprintf(GFP_KERNEL, "Color Pipeline %d", ops[i]->base.id);
+
+ i++;
+
+ /* 2nd op: 3x4 matrix */
+ ops[i] = kzalloc(sizeof(*ops[i]), GFP_KERNEL);
+ if (!ops[i]) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ ret = drm_crtc_colorop_ctm_3x4_init(dev, ops[i], crtc, DRM_COLOROP_FLAG_ALLOW_BYPASS);
+ if (ret)
+ goto err_colorop_init;
+
+ drm_colorop_set_next_property(ops[i - 1], ops[i]);
+
+ i++;
+
+ /* 3rd op: 3x4 matrix */
+ ops[i] = kzalloc(sizeof(*ops[i]), GFP_KERNEL);
+ if (!ops[i]) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ ret = drm_crtc_colorop_ctm_3x4_init(dev, ops[i], crtc, DRM_COLOROP_FLAG_ALLOW_BYPASS);
+ if (ret)
+ goto err_colorop_init;
+
+ drm_colorop_set_next_property(ops[i - 1], ops[i]);
+
+ i++;
+
+ /* 4th op: 1d curve */
+ ops[i] = kzalloc(sizeof(*ops[i]), GFP_KERNEL);
+ if (!ops[i]) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ ret = drm_crtc_colorop_curve_1d_init(dev, ops[i], crtc, supported_tfs,
+ DRM_COLOROP_FLAG_ALLOW_BYPASS);
+ if (ret)
+ goto err_colorop_init;
+
+ drm_colorop_set_next_property(ops[i - 1], ops[i]);
+
+ return 0;
+
+err_colorop_init:
+ kfree(ops[i]);
+
+cleanup:
+ for (j = 0; j < i; j++) {
+ drm_colorop_cleanup(ops[j]);
+ kfree(ops[j]);
+ }
+
+ return ret;
+}
+
int vkms_initialize_plane_colorops(struct drm_plane *plane)
{
struct drm_prop_enum_list pipeline;
@@ -119,3 +204,21 @@ int vkms_initialize_plane_colorops(struct drm_plane *plane)
return 0;
}
+
+int vkms_initialize_crtc_colorops(struct drm_crtc *crtc)
+{
+ struct drm_prop_enum_list pipeline;
+ int ret;
+
+ /* Add color pipeline */
+ ret = vkms_initialize_crtc_color_pipeline(crtc, &pipeline);
+ if (ret)
+ return ret;
+
+ /* Create COLOR_PIPELINE property and attach */
+ ret = drm_crtc_create_color_pipeline_property(crtc, &pipeline, 1);
+ if (ret)
+ return ret;
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c
index d4f87a2aa3359..621f008b165a6 100644
--- a/drivers/gpu/drm/vkms/vkms_composer.c
+++ b/drivers/gpu/drm/vkms/vkms_composer.c
@@ -495,7 +495,10 @@ static void blend(struct vkms_writeback_job *wb,
blend_line(plane[i], y, crtc_x_limit, stage_buffer, output_buffer);
}
- apply_lut(crtc_state, output_buffer);
+ if (crtc_state->base.color_pipeline_enabled)
+ color_transform(crtc_state->base.color_pipeline, output_buffer);
+ else
+ apply_lut(crtc_state, output_buffer);
*crc32 = crc32_le(*crc32, (void *)output_buffer->pixels, row_size);
diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index 8788df9edb7ca..a65c3638eff4d 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -34,7 +34,8 @@ EXPORT_SYMBOL_IF_KUNIT(vkms_config_create);
struct vkms_config *vkms_config_default_create(bool enable_cursor,
bool enable_writeback,
bool enable_overlay,
- bool enable_plane_pipeline)
+ bool enable_plane_pipeline,
+ bool enable_crtc_pipeline)
{
struct vkms_config *config;
struct vkms_config_plane *plane_cfg;
@@ -56,6 +57,7 @@ struct vkms_config *vkms_config_default_create(bool enable_cursor,
if (IS_ERR(crtc_cfg))
goto err_alloc;
vkms_config_crtc_set_writeback(crtc_cfg, enable_writeback);
+ vkms_config_crtc_set_default_pipeline(crtc_cfg, enable_crtc_pipeline);
if (vkms_config_plane_attach_crtc(plane_cfg, crtc_cfg))
goto err_alloc;
@@ -454,6 +456,7 @@ struct vkms_config_crtc *vkms_config_create_crtc(struct vkms_config *config)
crtc_cfg->config = config;
vkms_config_crtc_set_writeback(crtc_cfg, false);
+ vkms_config_crtc_set_default_pipeline(crtc_cfg, false);
list_add_tail(&crtc_cfg->link, &config->crtcs);
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index 8f7f286a4bdd7..e12e4065f01f0 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -61,6 +61,7 @@ struct vkms_config_plane {
* @link: Link to the others CRTCs in vkms_config
* @config: The vkms_config this CRTC belongs to
* @writeback: If true, a writeback buffer can be attached to the CRTC
+ * @default_pipeline: If true, CRTC will be created with the default pipeline.
* @crtc: Internal usage. This pointer should never be considered as valid.
* It can be used to store a temporary reference to a VKMS CRTC during
* device creation. This pointer is not managed by the configuration and
@@ -71,6 +72,7 @@ struct vkms_config_crtc {
struct vkms_config *config;
bool writeback;
+ bool default_pipeline;
/* Internal usage */
struct vkms_output *crtc;
@@ -205,7 +207,8 @@ struct vkms_config *vkms_config_create(const char *dev_name);
struct vkms_config *vkms_config_default_create(bool enable_cursor,
bool enable_writeback,
bool enable_overlay,
- bool enable_plane_pipeline);
+ bool enable_plane_pipeline,
+ bool enable_crtc_pipeline);
/**
* vkms_config_destroy() - Free a VKMS configuration
@@ -314,6 +317,30 @@ vkms_config_plane_set_default_pipeline(struct vkms_config_plane *plane_cfg,
plane_cfg->default_pipeline = default_pipeline;
}
+/**
+ * vkms_config_crtc_get_default_pipeline() - Return if the CRTC will
+ * be created with the default pipeline
+ * @crtc_cfg: CRTC to get the information from
+ */
+static inline bool
+vkms_config_crtc_get_default_pipeline(struct vkms_config_crtc *crtc_cfg)
+{
+ return crtc_cfg->default_pipeline;
+}
+
+/**
+ * vkms_config_crtc_set_default_pipeline() - Set if the CRTC will
+ * be created with the default pipeline
+ * @crtc_cfg: CRTC to configure the pipeline
+ * @default_pipeline: New default pipeline value
+ */
+static inline void
+vkms_config_crtc_set_default_pipeline(struct vkms_config_crtc *crtc_cfg,
+ bool default_pipeline)
+{
+ crtc_cfg->default_pipeline = default_pipeline;
+}
+
/**
* vkms_config_plane_attach_crtc - Attach a plane to a CRTC
* @plane_cfg: Plane to attach
diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c
index 9a7db1d510222..60c372c0ce2d8 100644
--- a/drivers/gpu/drm/vkms/vkms_crtc.c
+++ b/drivers/gpu/drm/vkms/vkms_crtc.c
@@ -10,6 +10,7 @@
#include <drm/drm_vblank.h>
#include <drm/drm_vblank_helper.h>
+#include "vkms_config.h"
#include "vkms_drv.h"
static bool vkms_crtc_handle_vblank_timeout(struct drm_crtc *crtc)
@@ -202,7 +203,7 @@ static const struct drm_crtc_helper_funcs vkms_crtc_helper_funcs = {
};
struct vkms_output *vkms_crtc_init(struct drm_device *dev, struct drm_plane *primary,
- struct drm_plane *cursor)
+ struct drm_plane *cursor, struct vkms_config_crtc *crtc_cfg)
{
struct vkms_output *vkms_out;
struct drm_crtc *crtc;
@@ -228,6 +229,9 @@ struct vkms_output *vkms_crtc_init(struct drm_device *dev, struct drm_plane *pri
drm_crtc_enable_color_mgmt(crtc, 0, false, VKMS_LUT_SIZE);
+ if (vkms_config_crtc_get_default_pipeline(crtc_cfg))
+ vkms_initialize_crtc_colorops(crtc);
+
spin_lock_init(&vkms_out->lock);
spin_lock_init(&vkms_out->composer_lock);
diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c
index dd1402f437736..39195540fe2b1 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.c
+++ b/drivers/gpu/drm/vkms/vkms_drv.c
@@ -55,6 +55,10 @@ static bool enable_plane_pipeline;
module_param_named(enable_plane_pipeline, enable_plane_pipeline, bool, 0444);
MODULE_PARM_DESC(enable_plane_pipeline, "Enable/Disable plane pipeline support");
+static bool enable_crtc_pipeline;
+module_param_named(enable_crtc_pipeline, enable_crtc_pipeline, bool, 0444);
+MODULE_PARM_DESC(enable_crtc_pipeline, "Enable/Disable CRTC pipeline support");
+
static bool create_default_dev = true;
module_param_named(create_default_dev, create_default_dev, bool, 0444);
MODULE_PARM_DESC(create_default_dev, "Create or not the default VKMS device");
@@ -232,7 +236,8 @@ static int __init vkms_init(void)
return 0;
config = vkms_config_default_create(enable_cursor, enable_writeback,
- enable_overlay, enable_plane_pipeline);
+ enable_overlay, enable_plane_pipeline,
+ enable_crtc_pipeline);
if (IS_ERR(config))
return PTR_ERR(config);
diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
index bdeb52623f4d6..1688c885f2285 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.h
+++ b/drivers/gpu/drm/vkms/vkms_drv.h
@@ -229,6 +229,7 @@ struct vkms_output {
};
struct vkms_config;
+struct vkms_config_crtc;
struct vkms_config_plane;
/**
@@ -287,10 +288,12 @@ void vkms_destroy(struct vkms_config *config);
* @crtc: uninitialized CRTC device
* @primary: primary plane to attach to the CRTC
* @cursor: plane to attach to the CRTC
+ * @crtc_cfg: CRTC configuration
*/
struct vkms_output *vkms_crtc_init(struct drm_device *dev,
struct drm_plane *primary,
- struct drm_plane *cursor);
+ struct drm_plane *cursor,
+ struct vkms_config_crtc *crtc_cfg);
/**
* vkms_output_init() - Initialize all sub-components needed for a VKMS device.
@@ -325,5 +328,6 @@ int vkms_enable_writeback_connector(struct vkms_device *vkmsdev, struct vkms_out
/* Colorops */
int vkms_initialize_plane_colorops(struct drm_plane *plane);
+int vkms_initialize_crtc_colorops(struct drm_crtc *crtc);
#endif /* _VKMS_DRV_H_ */
diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
index 86ce07a617f52..a0856ba90ac24 100644
--- a/drivers/gpu/drm/vkms/vkms_output.c
+++ b/drivers/gpu/drm/vkms/vkms_output.c
@@ -34,7 +34,8 @@ int vkms_output_init(struct vkms_device *vkmsdev)
cursor = vkms_config_crtc_cursor_plane(vkmsdev->config, crtc_cfg);
crtc_cfg->crtc = vkms_crtc_init(dev, &primary->plane->base,
- cursor ? &cursor->plane->base : NULL);
+ cursor ? &cursor->plane->base : NULL,
+ crtc_cfg);
if (IS_ERR(crtc_cfg->crtc)) {
DRM_ERROR("Failed to allocate CRTC\n");
return PTR_ERR(crtc_cfg->crtc);
--
2.51.0
Powered by blists - more mailing lists