[PATCH 1/5] drm/vkms: make argb_u16_to_RGB565 round resulting values

From: Matheus Alves de Almeida

Date: Sun Sep 27 2026 - 20:55:42 EST


Currently, argb_u16_to_RGB565() truncates the resulting channel values.
Use drm_fixp2int_round() to round them to the nearest representable
RGB565 values.

Restore the rounding behavior from commit
ab87f558dcfb ("drm/vkms: Fix RGB565 pixel conversion") while adding a
separate helper for channel conversion.

Fixes: cc4fd2934d41 ("drm/vkms: Isolate writeback pixel conversion functions")
Signed-off-by: Matheus Alves de Almeida <matheus.aalmeida@xxxxxxxxxxxx>
---
drivers/gpu/drm/vkms/vkms_formats.c | 35 ++++++++++++++++++++---------
1 file changed, 25 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/vkms/vkms_formats.c b/drivers/gpu/drm/vkms/vkms_formats.c
index dfb8e13cb..6d7853e87 100644
--- a/drivers/gpu/drm/vkms/vkms_formats.c
+++ b/drivers/gpu/drm/vkms/vkms_formats.c
@@ -639,20 +639,35 @@ static void argb_u16_to_XRGB16161616(u8 *out_pixel, const struct pixel_argb_u16
pixel[0] = cpu_to_le16(in_pixel->b);
}

-static void argb_u16_to_RGB565(u8 *out_pixel, const struct pixel_argb_u16 *in_pixel)
+static u16 u16_to_channel(int size, u16 in)
{
- __le16 *pixel = (__le16 *)out_pixel;
+ s64 fp_ratio = drm_fixp_div(drm_int2fixp(65535), drm_int2fixp((1 << size) - 1));
+ s64 fp_channel = drm_int2fixp(in);

- s64 fp_rb_ratio = drm_fixp_div(drm_int2fixp(65535), drm_int2fixp(31));
- s64 fp_g_ratio = drm_fixp_div(drm_int2fixp(65535), drm_int2fixp(63));
+ return drm_fixp2int_round(drm_fixp_div(fp_channel, fp_ratio));
+}
+
+static void argb_u16_to_channels(u16 *out_r, u16 *out_g, u16 *out_b, u16 *out_a,
+ unsigned int r_size, unsigned int g_size,
+ unsigned int b_size, unsigned int a_size,
+ const struct pixel_argb_u16 *in_pixel)
+{
+ if (r_size)
+ *out_r = u16_to_channel(r_size, in_pixel->r);
+ if (g_size)
+ *out_g = u16_to_channel(g_size, in_pixel->g);
+ if (b_size)
+ *out_b = u16_to_channel(b_size, in_pixel->b);
+ if (a_size)
+ *out_a = u16_to_channel(a_size, in_pixel->a);
+}

- s64 fp_r = drm_int2fixp(in_pixel->r);
- s64 fp_g = drm_int2fixp(in_pixel->g);
- s64 fp_b = drm_int2fixp(in_pixel->b);
+static void argb_u16_to_RGB565(u8 *out_pixel, const struct pixel_argb_u16 *in_pixel)
+{
+ __le16 *pixel = (__le16 *)out_pixel;
+ u16 r, g, b;

- u16 r = drm_fixp2int(drm_fixp_div(fp_r, fp_rb_ratio));
- u16 g = drm_fixp2int(drm_fixp_div(fp_g, fp_g_ratio));
- u16 b = drm_fixp2int(drm_fixp_div(fp_b, fp_rb_ratio));
+ argb_u16_to_channels(&r, &g, &b, NULL, 5, 6, 5, 0, in_pixel);

*pixel = cpu_to_le16(r << 11 | g << 5 | b);
}
--
2.43.0