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 <[email protected]>
---
 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

Reply via email to