@samitouri / QOSamiQemu / commits / d0f1fdc37c

ati-vga: Fix colors when frame buffer endianness does not match host

When writing pixels we have to take into account if the frame buffer endianness matches the host endianness or we need to swap to correct endianness. This caused wrong colors e.g. with PPC Linux guest that uses big endian frame buffer when running on little endian host. Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu> Tested-by: Chad Jablonski <chad@jablonski.xyz> Reviewed-by: Chad Jablonski <chad@jablonski.xyz> Message-ID: <759ed5e3b019cce94e9a4ef003f1fc2e0cea2ec1.1774110169.git.balaton@eik.bme.hu> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>

BALATON Zoltan committed Mar 21, 2026 at 17:30 UTC d0f1fdc37c6762cc4f0736e973d62ea145913e9b
1 file changed +29 -11
hw/display/ati_2d.c
+29 -11
@@ -50,6 +50,7 @@ typedef struct {
50 bool host_data_active;
51 bool left_to_right;
52 bool top_to_bottom;
53 + bool need_swap;
54 uint32_t frgd_clr;
55 const uint8_t *palette;
56 const uint8_t *vram_end;
@@ -89,6 +90,7 @@ static void setup_2d_blt_ctx(const ATIVGAState *s, ATI2DCtx *ctx)
90 ctx->host_data_active = s->host_data.active;
91 ctx->left_to_right = s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT;
92 ctx->top_to_bottom = s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM;
93 + ctx->need_swap = HOST_BIG_ENDIAN != s->vga.big_endian_fb ? true : false;
94 ctx->frgd_clr = s->regs.dp_brush_frgd_clr;
95 ctx->palette = s->vga.palette;
96 ctx->dst_offset = s->regs.dst_offset;
@@ -131,6 +133,17 @@ static void setup_2d_blt_ctx(const ATIVGAState *s, ATI2DCtx *ctx)
133 (ctx->top_to_bottom ? 'v' : '^'));
134 }
135
136 +static uint32_t make_filler(int bpp, uint32_t color)
137 +{
138 + if (bpp < 24) {
139 + color |= color << 16;
140 + if (bpp < 15) {
141 + color |= color << 8;
142 + }
143 + }
144 + return color;
145 +}
146 +
147 static bool ati_2d_do_blt(ATI2DCtx *ctx, uint8_t use_pixman)
148 {
149 QemuRect vis_src, vis_dst;
@@ -255,7 +268,7 @@ static bool ati_2d_do_blt(ATI2DCtx *ctx, uint8_t use_pixman)
268
269 switch (ctx->rop3) {
270 case ROP3_PATCOPY:
258 - filler = ctx->frgd_clr;
271 + filler = make_filler(ctx->bpp, ctx->frgd_clr);
272 break;
273 case ROP3_BLACKNESS:
274 filler = 0xffUL << 24 | rgb_to_pixel32(ctx->palette[0],
@@ -268,10 +281,12 @@ static bool ati_2d_do_blt(ATI2DCtx *ctx, uint8_t use_pixman)
281 ctx->palette[5]);
282 break;
283 }
271 -
284 DPRINTF("pixman_fill(%p, %ld, %d, %d, %d, %d, %d, %x)\n",
285 ctx->dst_bits, ctx->dst_stride / sizeof(uint32_t), ctx->bpp,
286 vis_dst.x, vis_dst.y, vis_dst.width, vis_dst.height, filler);
287 + if (ctx->need_swap) {
288 + bswap32s(&filler);
289 + }
290 #ifdef CONFIG_PIXMAN
291 if (!(use_pixman & BIT(0)) ||
292 !pixman_fill((uint32_t *)ctx->dst_bits,
@@ -325,11 +340,8 @@ void ati_2d_blt(ATIVGAState *s)
340 bool ati_host_data_flush(ATIVGAState *s)
341 {
342 ATI2DCtx ctx, chunk;
328 - uint32_t fg = s->regs.dp_src_frgd_clr;
329 - uint32_t bg = s->regs.dp_src_bkgd_clr;
343 unsigned bypp, pix_count, row, col, idx;
344 uint8_t pix_buf[ATI_HOST_DATA_ACC_BITS * sizeof(uint32_t)];
332 - uint32_t byte_pix_order = s->regs.dp_datatype & DP_BYTE_PIX_ORDER;
345 uint32_t src_source = s->regs.dp_mix & DP_SRC_SOURCE;
346 uint32_t src_datatype = s->regs.dp_datatype & DP_SRC_DATATYPE;
347
@@ -360,21 +372,27 @@ bool ati_host_data_flush(ATIVGAState *s)
372 }
373
374 bypp = ctx.bpp / 8;
363 -
375 + pix_count = ATI_HOST_DATA_ACC_BITS;
376 if (src_datatype == SRC_COLOR) {
365 - pix_count = ATI_HOST_DATA_ACC_BITS / ctx.bpp;
366 - memcpy(pix_buf, &s->host_data.acc[0], sizeof(s->host_data.acc));
377 + pix_count /= ctx.bpp;
378 + memcpy(pix_buf, s->host_data.acc, sizeof(s->host_data.acc));
379 } else {
368 - pix_count = ATI_HOST_DATA_ACC_BITS;
380 /* Expand monochrome bits to color pixels */
381 + uint32_t byte_pix_order = s->regs.dp_datatype & DP_BYTE_PIX_ORDER;
382 + uint32_t fg = make_filler(ctx.bpp, s->regs.dp_src_frgd_clr);
383 + uint32_t bg = make_filler(ctx.bpp, s->regs.dp_src_bkgd_clr);
384 +
385 + if (ctx.need_swap) {
386 + bswap32s(&fg);
387 + bswap32s(&bg);
388 + }
389 idx = 0;
390 for (int word = 0; word < 4; word++) {
391 for (int byte = 0; byte < 4; byte++) {
392 uint8_t byte_val = s->host_data.acc[word] >> (byte * 8);
393 for (int i = 0; i < 8; i++) {
394 bool is_fg = byte_val & BIT(byte_pix_order ? i : 7 - i);
376 - uint32_t color = is_fg ? fg : bg;
377 - stn_he_p(&pix_buf[idx], bypp, color);
395 + stn_he_p(&pix_buf[idx], bypp, is_fg ? fg : bg);
396 idx += bypp;
397 }
398 }