summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/vkms/vkms_composer.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/vkms/vkms_composer.c')
-rw-r--r--drivers/gpu/drm/vkms/vkms_composer.c136
1 files changed, 119 insertions, 17 deletions
diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c
index fa269d279e25..3cf3f26e0d8e 100644
--- a/drivers/gpu/drm/vkms/vkms_composer.c
+++ b/drivers/gpu/drm/vkms/vkms_composer.c
@@ -8,10 +8,13 @@
#include <drm/drm_fourcc.h>
#include <drm/drm_fixed.h>
#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_print.h>
#include <drm/drm_vblank.h>
#include <linux/minmax.h>
+#include <kunit/visibility.h>
-#include "vkms_drv.h"
+#include "vkms_composer.h"
+#include "vkms_luts.h"
static u16 pre_mul_blend_channel(u16 src, u16 dst, u16 alpha)
{
@@ -60,7 +63,7 @@ static void fill_background(const struct pixel_argb_u16 *background_color,
}
// lerp(a, b, t) = a + (b - a) * t
-static u16 lerp_u16(u16 a, u16 b, s64 t)
+VISIBLE_IF_KUNIT u16 lerp_u16(u16 a, u16 b, s64 t)
{
s64 a_fp = drm_int2fixp(a);
s64 b_fp = drm_int2fixp(b);
@@ -69,27 +72,18 @@ static u16 lerp_u16(u16 a, u16 b, s64 t)
return drm_fixp2int_round(a_fp + delta);
}
+EXPORT_SYMBOL_IF_KUNIT(lerp_u16);
-static s64 get_lut_index(const struct vkms_color_lut *lut, u16 channel_value)
+VISIBLE_IF_KUNIT s64 get_lut_index(const struct vkms_color_lut *lut, u16 channel_value)
{
s64 color_channel_fp = drm_int2fixp(channel_value);
return drm_fixp_mul(color_channel_fp, lut->channel_value2index_ratio);
}
+EXPORT_SYMBOL_IF_KUNIT(get_lut_index);
-/*
- * This enum is related to the positions of the variables inside
- * `struct drm_color_lut`, so the order of both needs to be the same.
- */
-enum lut_channel {
- LUT_RED = 0,
- LUT_GREEN,
- LUT_BLUE,
- LUT_RESERVED
-};
-
-static u16 apply_lut_to_channel_value(const struct vkms_color_lut *lut, u16 channel_value,
- enum lut_channel channel)
+VISIBLE_IF_KUNIT u16 apply_lut_to_channel_value(const struct vkms_color_lut *lut, u16 channel_value,
+ enum lut_channel channel)
{
s64 lut_index = get_lut_index(lut, channel_value);
u16 *floor_lut_value, *ceil_lut_value;
@@ -114,6 +108,8 @@ static u16 apply_lut_to_channel_value(const struct vkms_color_lut *lut, u16 chan
return lerp_u16(floor_channel_value, ceil_channel_value,
lut_index & DRM_FIXED_DECIMAL_MASK);
}
+EXPORT_SYMBOL_IF_KUNIT(apply_lut_to_channel_value);
+
static void apply_lut(const struct vkms_crtc_state *crtc_state, struct line_buffer *output_buffer)
{
@@ -132,6 +128,112 @@ static void apply_lut(const struct vkms_crtc_state *crtc_state, struct line_buff
}
}
+VISIBLE_IF_KUNIT void apply_3x4_matrix(struct pixel_argb_s32 *pixel,
+ const struct drm_color_ctm_3x4 *matrix)
+{
+ s64 rf, gf, bf;
+ s64 r, g, b;
+
+ r = drm_int2fixp(pixel->r);
+ g = drm_int2fixp(pixel->g);
+ b = drm_int2fixp(pixel->b);
+
+ rf = drm_fixp_mul(drm_sm2fixp(matrix->matrix[0]), r) +
+ drm_fixp_mul(drm_sm2fixp(matrix->matrix[1]), g) +
+ drm_fixp_mul(drm_sm2fixp(matrix->matrix[2]), b) +
+ drm_sm2fixp(matrix->matrix[3]);
+
+ gf = drm_fixp_mul(drm_sm2fixp(matrix->matrix[4]), r) +
+ drm_fixp_mul(drm_sm2fixp(matrix->matrix[5]), g) +
+ drm_fixp_mul(drm_sm2fixp(matrix->matrix[6]), b) +
+ drm_sm2fixp(matrix->matrix[7]);
+
+ bf = drm_fixp_mul(drm_sm2fixp(matrix->matrix[8]), r) +
+ drm_fixp_mul(drm_sm2fixp(matrix->matrix[9]), g) +
+ drm_fixp_mul(drm_sm2fixp(matrix->matrix[10]), b) +
+ drm_sm2fixp(matrix->matrix[11]);
+
+ pixel->r = drm_fixp2int_round(rf);
+ pixel->g = drm_fixp2int_round(gf);
+ pixel->b = drm_fixp2int_round(bf);
+}
+EXPORT_SYMBOL_IF_KUNIT(apply_3x4_matrix);
+
+static void apply_colorop(struct pixel_argb_s32 *pixel, struct drm_colorop *colorop)
+{
+ struct drm_colorop_state *colorop_state = colorop->state;
+ struct drm_device *dev = colorop->dev;
+
+ if (colorop->type == DRM_COLOROP_1D_CURVE) {
+ switch (colorop_state->curve_1d_type) {
+ case DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF:
+ pixel->r = apply_lut_to_channel_value(&srgb_inv_eotf, pixel->r, LUT_RED);
+ pixel->g = apply_lut_to_channel_value(&srgb_inv_eotf, pixel->g, LUT_GREEN);
+ pixel->b = apply_lut_to_channel_value(&srgb_inv_eotf, pixel->b, LUT_BLUE);
+ break;
+ case DRM_COLOROP_1D_CURVE_SRGB_EOTF:
+ pixel->r = apply_lut_to_channel_value(&srgb_eotf, pixel->r, LUT_RED);
+ pixel->g = apply_lut_to_channel_value(&srgb_eotf, pixel->g, LUT_GREEN);
+ pixel->b = apply_lut_to_channel_value(&srgb_eotf, pixel->b, LUT_BLUE);
+ break;
+ default:
+ drm_WARN_ONCE(dev, true,
+ "unknown colorop 1D curve type %d\n",
+ colorop_state->curve_1d_type);
+ break;
+ }
+ } else if (colorop->type == DRM_COLOROP_CTM_3X4) {
+ if (colorop_state->data)
+ apply_3x4_matrix(pixel,
+ (struct drm_color_ctm_3x4 *)colorop_state->data->data);
+ }
+}
+
+static void pre_blend_color_transform(const struct vkms_plane_state *plane_state,
+ struct line_buffer *output_buffer)
+{
+ struct pixel_argb_s32 pixel;
+
+ for (size_t x = 0; x < output_buffer->n_pixels; x++) {
+ struct drm_colorop *colorop = plane_state->base.base.color_pipeline;
+
+ /*
+ * Some operations, such as applying a BT709 encoding matrix,
+ * followed by a decoding matrix, require that we preserve
+ * values above 1.0 and below 0.0 until the end of the pipeline.
+ *
+ * Pack the 16-bit UNORM values into s32 to give us head-room to
+ * avoid clipping until we're at the end of the pipeline. Clip
+ * intentionally at the end of the pipeline before packing
+ * UNORM values back into u16.
+ */
+ pixel.a = output_buffer->pixels[x].a;
+ pixel.r = output_buffer->pixels[x].r;
+ pixel.g = output_buffer->pixels[x].g;
+ pixel.b = output_buffer->pixels[x].b;
+
+ while (colorop) {
+ struct drm_colorop_state *colorop_state;
+
+ colorop_state = colorop->state;
+
+ if (!colorop_state)
+ return;
+
+ if (!colorop_state->bypass)
+ apply_colorop(&pixel, colorop);
+
+ colorop = colorop->next;
+ }
+
+ /* clamp values */
+ output_buffer->pixels[x].a = clamp_val(pixel.a, 0, 0xffff);
+ output_buffer->pixels[x].r = clamp_val(pixel.r, 0, 0xffff);
+ output_buffer->pixels[x].g = clamp_val(pixel.g, 0, 0xffff);
+ output_buffer->pixels[x].b = clamp_val(pixel.b, 0, 0xffff);
+ }
+}
+
/**
* direction_for_rotation() - Get the correct reading direction for a given rotation
*
@@ -347,7 +449,7 @@ static void blend_line(struct vkms_plane_state *current_plane, int y,
*/
current_plane->pixel_read_line(current_plane, src_x_start, src_y_start, direction,
pixel_count, &stage_buffer->pixels[dst_x_start]);
-
+ pre_blend_color_transform(current_plane, stage_buffer);
pre_mul_alpha_blend(stage_buffer, output_buffer,
dst_x_start, pixel_count);
}