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
}