Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/vkms: add 3x4 matrix in color pipeline

We add two 3x4 matrices into the VKMS color pipeline. The reason
we're adding matrices is so that we can test that application
of a matrix and its inverse yields an output equal to the input
image.

One complication with the matrix implementation has to do with
the fact that the matrix entries are in signed-magnitude fixed
point, whereas the drm_fixed.h implementation uses 2s-complement.
The latter one is the one that we want for easy addition and
subtraction, so we convert all entries to 2s-complement.

Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Harry Wentland <harry.wentland@amd.com>
Reviewed-by: Daniel Stone <daniels@collabora.com>
Signed-off-by: Simon Ser <contact@emersion.fr>
Link: https://patch.msgid.link/20251115000237.3561250-21-alex.hung@amd.com

authored by

Harry Wentland and committed by
Simon Ser
ea3f6baf bff4d3cd

+67 -2
+34 -2
drivers/gpu/drm/vkms/vkms_colorop.c
··· 12 12 BIT(DRM_COLOROP_1D_CURVE_SRGB_EOTF) | 13 13 BIT(DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF); 14 14 15 - #define MAX_COLOR_PIPELINE_OPS 2 15 + #define MAX_COLOR_PIPELINE_OPS 4 16 16 17 17 static int vkms_initialize_color_pipeline(struct drm_plane *plane, struct drm_prop_enum_list *list) 18 18 { ··· 40 40 41 41 i++; 42 42 43 - /* 2nd op: 1d curve */ 43 + /* 2nd op: 3x4 matrix */ 44 + ops[i] = kzalloc(sizeof(*ops[i]), GFP_KERNEL); 45 + if (!ops[i]) { 46 + drm_err(dev, "KMS: Failed to allocate colorop\n"); 47 + ret = -ENOMEM; 48 + goto cleanup; 49 + } 50 + 51 + ret = drm_plane_colorop_ctm_3x4_init(dev, ops[i], plane); 52 + if (ret) 53 + goto cleanup; 54 + 55 + drm_colorop_set_next_property(ops[i - 1], ops[i]); 56 + 57 + i++; 58 + 59 + /* 3rd op: 3x4 matrix */ 60 + ops[i] = kzalloc(sizeof(*ops[i]), GFP_KERNEL); 61 + if (!ops[i]) { 62 + drm_err(dev, "KMS: Failed to allocate colorop\n"); 63 + ret = -ENOMEM; 64 + goto cleanup; 65 + } 66 + 67 + ret = drm_plane_colorop_ctm_3x4_init(dev, ops[i], plane); 68 + if (ret) 69 + goto cleanup; 70 + 71 + drm_colorop_set_next_property(ops[i - 1], ops[i]); 72 + 73 + i++; 74 + 75 + /* 4th op: 1d curve */ 44 76 ops[i] = kzalloc(sizeof(*ops[i]), GFP_KERNEL); 45 77 if (!ops[i]) { 46 78 drm_err(dev, "KMS: Failed to allocate colorop\n");
+33
drivers/gpu/drm/vkms/vkms_composer.c
··· 128 128 } 129 129 } 130 130 131 + static void apply_3x4_matrix(struct pixel_argb_s32 *pixel, const struct drm_color_ctm_3x4 *matrix) 132 + { 133 + s64 rf, gf, bf; 134 + s64 r, g, b; 135 + 136 + r = drm_int2fixp(pixel->r); 137 + g = drm_int2fixp(pixel->g); 138 + b = drm_int2fixp(pixel->b); 139 + 140 + rf = drm_fixp_mul(drm_sm2fixp(matrix->matrix[0]), r) + 141 + drm_fixp_mul(drm_sm2fixp(matrix->matrix[1]), g) + 142 + drm_fixp_mul(drm_sm2fixp(matrix->matrix[2]), b) + 143 + drm_sm2fixp(matrix->matrix[3]); 144 + 145 + gf = drm_fixp_mul(drm_sm2fixp(matrix->matrix[4]), r) + 146 + drm_fixp_mul(drm_sm2fixp(matrix->matrix[5]), g) + 147 + drm_fixp_mul(drm_sm2fixp(matrix->matrix[6]), b) + 148 + drm_sm2fixp(matrix->matrix[7]); 149 + 150 + bf = drm_fixp_mul(drm_sm2fixp(matrix->matrix[8]), r) + 151 + drm_fixp_mul(drm_sm2fixp(matrix->matrix[9]), g) + 152 + drm_fixp_mul(drm_sm2fixp(matrix->matrix[10]), b) + 153 + drm_sm2fixp(matrix->matrix[11]); 154 + 155 + pixel->r = drm_fixp2int_round(rf); 156 + pixel->g = drm_fixp2int_round(gf); 157 + pixel->b = drm_fixp2int_round(bf); 158 + } 159 + 131 160 static void apply_colorop(struct pixel_argb_s32 *pixel, struct drm_colorop *colorop) 132 161 { 133 162 struct drm_colorop_state *colorop_state = colorop->state; ··· 180 151 colorop_state->curve_1d_type); 181 152 break; 182 153 } 154 + } else if (colorop->type == DRM_COLOROP_CTM_3X4) { 155 + if (colorop_state->data) 156 + apply_3x4_matrix(pixel, 157 + (struct drm_color_ctm_3x4 *)colorop_state->data->data); 183 158 } 184 159 } 185 160