[PATCH v2 6/7] ati-vga: Add expand_colors() helper for monochrome color expansion

Chad Jablonski posted 7 patches 1 week, 4 days ago
[PATCH v2 6/7] ati-vga: Add expand_colors() helper for monochrome color expansion
Posted by Chad Jablonski 1 week, 4 days ago
Convert 1bpp monochrome images to 32bpp ARGB given a foreground and
background color. This also supports most significant and least
significant bit ordering.

This is useful for host data transfers of glyphs when drawing text in X.

Signed-off-by: Chad Jablonski <chad@jablonski.xyz>
---
 hw/display/ati_2d.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/hw/display/ati_2d.c b/hw/display/ati_2d.c
index 15cf29a061..181bf634f0 100644
--- a/hw/display/ati_2d.c
+++ b/hw/display/ati_2d.c
@@ -45,6 +45,28 @@ static int ati_bpp_from_datatype(ATIVGAState *s)
 }
 
 #define DEFAULT_CNTL (s->regs.dp_gui_master_cntl & GMC_DST_PITCH_OFFSET_CNTL)
+/* Convert 1bpp monochrome data to 32bpp ARGB using color expansion */
+static void expand_colors(uint8_t *color_dst, const uint8_t *mono_src,
+                          uint32_t width, uint32_t height,
+                          uint32_t fg_color, uint32_t bg_color,
+                          bool lsb_to_msb)
+{
+    uint32_t byte, color;
+    uint8_t *pixel;
+    int i, j, bit;
+    /* Rows are 32-bit aligned */
+    int bytes_per_row = ((width + 31) / 32) * 4;
+
+    for (i = 0; i < height; i++) {
+        for (j = 0; j < width; j++) {
+            byte = mono_src[i * bytes_per_row + (j / 8)];
+            bit = lsb_to_msb ? 7 - (j % 8) : j % 8;
+            color = (byte >> bit) & 0x1 ? fg_color : bg_color;
+            pixel = &color_dst[(i * width + j) * 4];
+            memcpy(pixel, &color, sizeof(color));
+        }
+    }
+}
 
 void ati_2d_blt(ATIVGAState *s)
 {
-- 
2.51.0
Re: [PATCH v2 6/7] ati-vga: Add expand_colors() helper for monochrome color expansion
Posted by BALATON Zoltan 1 week, 4 days ago
On Sun, 2 Nov 2025, Chad Jablonski wrote:
> Convert 1bpp monochrome images to 32bpp ARGB given a foreground and
> background color. This also supports most significant and least
> significant bit ordering.
>
> This is useful for host data transfers of glyphs when drawing text in X.
>
> Signed-off-by: Chad Jablonski <chad@jablonski.xyz>
> ---
> hw/display/ati_2d.c | 22 ++++++++++++++++++++++
> 1 file changed, 22 insertions(+)
>
> diff --git a/hw/display/ati_2d.c b/hw/display/ati_2d.c
> index 15cf29a061..181bf634f0 100644
> --- a/hw/display/ati_2d.c
> +++ b/hw/display/ati_2d.c
> @@ -45,6 +45,28 @@ static int ati_bpp_from_datatype(ATIVGAState *s)
> }
>
> #define DEFAULT_CNTL (s->regs.dp_gui_master_cntl & GMC_DST_PITCH_OFFSET_CNTL)
> +/* Convert 1bpp monochrome data to 32bpp ARGB using color expansion */
> +static void expand_colors(uint8_t *color_dst, const uint8_t *mono_src,
> +                          uint32_t width, uint32_t height,
> +                          uint32_t fg_color, uint32_t bg_color,
> +                          bool lsb_to_msb)
> +{
> +    uint32_t byte, color;
> +    uint8_t *pixel;
> +    int i, j, bit;
> +    /* Rows are 32-bit aligned */
> +    int bytes_per_row = ((width + 31) / 32) * 4;

I think there's some QEMU_ALIGN macro for that maybe in qemu/osdep.h?

> +
> +    for (i = 0; i < height; i++) {
> +        for (j = 0; j < width; j++) {
> +            byte = mono_src[i * bytes_per_row + (j / 8)];
> +            bit = lsb_to_msb ? 7 - (j % 8) : j % 8;
> +            color = (byte >> bit) & 0x1 ? fg_color : bg_color;
> +            pixel = &color_dst[(i * width + j) * 4];
> +            memcpy(pixel, &color, sizeof(color));

Since it's just writing a 32 bit value maybe cast and = would be faster 
than calling memcpy for this.

Regards,
BALATON Zoltan

> +        }
> +    }
> +}
>
> void ati_2d_blt(ATIVGAState *s)
> {
>
Re: [PATCH v2 6/7] ati-vga: Add expand_colors() helper for monochrome color expansion
Posted by Chad Jablonski 3 days, 22 hours ago
>> +    int bytes_per_row = ((width + 31) / 32) * 4;
>
> I think there's some QEMU_ALIGN macro for that maybe in qemu/osdep.h?
>
>> +
>> +    for (i = 0; i < height; i++) {
>> +        for (j = 0; j < width; j++) {
>> +            byte = mono_src[i * bytes_per_row + (j / 8)];
>> +            bit = lsb_to_msb ? 7 - (j % 8) : j % 8;
>> +            color = (byte >> bit) & 0x1 ? fg_color : bg_color;
>> +            pixel = &color_dst[(i * width + j) * 4];
>> +            memcpy(pixel, &color, sizeof(color));
>
> Since it's just writing a 32 bit value maybe cast and = would be faster 
> than calling memcpy for this.
>

Yep, good call! I'll make these changes in v3 also.