@@ -159,7 +159,7 @@ static void apply_lut(const struct vkms_crtc_state *crtc_state, struct line_buff
}
}
-static void apply_colorop(struct pixel_argb_u16 *pixel, struct drm_colorop *colorop)
+static void apply_colorop(struct pixel_argb_s32 *pixel, struct drm_colorop *colorop)
{
struct drm_colorop_state *colorop_state = colorop->state;
@@ -186,9 +186,26 @@ static void apply_colorop(struct pixel_argb_u16 *pixel, struct drm_colorop *colo
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;
@@ -198,10 +215,16 @@ static void pre_blend_color_transform(const struct vkms_plane_state *plane_state
return;
if (!colorop_state->bypass)
- apply_colorop(&output_buffer->pixels[x], colorop);
+ 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);
}
}
@@ -36,6 +36,10 @@ struct vkms_frame_info {
unsigned int cpp;
};
+struct pixel_argb_s32 {
+ s32 a, r, g, b;
+};
+
struct pixel_argb_u16 {
u16 a, r, g, b;
};