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>
---
hw/display/ati_2d.c | 27 +++++++++++++++++----------
1 file changed, 17 insertions(+), 10 deletions(-)
diff --git a/hw/display/ati_2d.c b/hw/display/ati_2d.c
index 37fe6c17ee..accc7b12b4 100644
--- a/hw/display/ati_2d.c
+++ b/hw/display/ati_2d.c
@@ -50,6 +50,7 @@ typedef struct {
bool host_data_active;
bool left_to_right;
bool top_to_bottom;
+ bool need_swap;
uint32_t frgd_clr;
const uint8_t *palette;
const uint8_t *vram_end;
@@ -89,6 +90,7 @@ static void setup_2d_blt_ctx(const ATIVGAState *s, ATI2DCtx *ctx)
ctx->host_data_active = s->host_data.active;
ctx->left_to_right = s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT;
ctx->top_to_bottom = s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM;
+ ctx->need_swap = HOST_BIG_ENDIAN != s->vga.big_endian_fb ? true : false;
ctx->frgd_clr = s->regs.dp_brush_frgd_clr;
ctx->palette = s->vga.palette;
ctx->dst_offset = s->regs.dst_offset;
@@ -268,10 +270,12 @@ static bool ati_2d_do_blt(ATI2DCtx *ctx, uint8_t use_pixman)
ctx->palette[5]);
break;
}
-
DPRINTF("pixman_fill(%p, %ld, %d, %d, %d, %d, %d, %x)\n",
ctx->dst_bits, ctx->dst_stride / sizeof(uint32_t), ctx->bpp,
vis_dst.x, vis_dst.y, vis_dst.width, vis_dst.height, filler);
+ if (ctx->need_swap) {
+ bswap32s(&filler);
+ }
#ifdef CONFIG_PIXMAN
if (!(use_pixman & BIT(0)) ||
!pixman_fill((uint32_t *)ctx->dst_bits,
@@ -325,11 +329,8 @@ void ati_2d_blt(ATIVGAState *s)
bool ati_host_data_flush(ATIVGAState *s)
{
ATI2DCtx ctx, chunk;
- uint32_t fg = s->regs.dp_src_frgd_clr;
- uint32_t bg = s->regs.dp_src_bkgd_clr;
unsigned bypp, pix_count, row, col, idx;
uint8_t pix_buf[ATI_HOST_DATA_ACC_BITS * sizeof(uint32_t)];
- uint32_t byte_pix_order = s->regs.dp_datatype & DP_BYTE_PIX_ORDER;
uint32_t src_source = s->regs.dp_mix & DP_SRC_SOURCE;
uint32_t src_datatype = s->regs.dp_datatype & DP_SRC_DATATYPE;
@@ -360,21 +361,27 @@ bool ati_host_data_flush(ATIVGAState *s)
}
bypp = ctx.bpp / 8;
-
+ pix_count = ATI_HOST_DATA_ACC_BITS;
if (src_datatype == SRC_COLOR) {
- pix_count = ATI_HOST_DATA_ACC_BITS / ctx.bpp;
- memcpy(pix_buf, &s->host_data.acc[0], sizeof(s->host_data.acc));
+ pix_count /= ctx.bpp;
+ memcpy(pix_buf, s->host_data.acc, sizeof(s->host_data.acc));
} else {
- pix_count = ATI_HOST_DATA_ACC_BITS;
/* Expand monochrome bits to color pixels */
+ uint32_t byte_pix_order = s->regs.dp_datatype & DP_BYTE_PIX_ORDER;
+ uint32_t fg = s->regs.dp_src_frgd_clr;
+ uint32_t bg = s->regs.dp_src_bkgd_clr;
+
+ if (ctx.need_swap) {
+ bswap32s(&fg);
+ bswap32s(&bg);
+ }
idx = 0;
for (int word = 0; word < 4; word++) {
for (int byte = 0; byte < 4; byte++) {
uint8_t byte_val = s->host_data.acc[word] >> (byte * 8);
for (int i = 0; i < 8; i++) {
bool is_fg = byte_val & BIT(byte_pix_order ? i : 7 - i);
- uint32_t color = is_fg ? fg : bg;
- stn_he_p(&pix_buf[idx], bypp, color);
+ stn_he_p(&pix_buf[idx], bypp, is_fg ? fg : bg);
idx += bypp;
}
}
--
2.41.3
This works in the 24/32bpp case. Before this I see a yellow background in fluxbox, after I see gray. I did notice that the existing big_endian_fb boolean in ati_vga_switch_mode doesn't distinguish between big endian 32-bit and 16-bit swapping. In the 16bpp case I see a black background in fluxbox. I did a quick and dirty test and replaced the bswap32s with a 16-bit byte swap and then 16bpp displays the gray background correctly. This is a pre-existing issue but I thought it was worth pointing out. That said this fixes things for 24/32bpp and is an improvement. Tested-by: Chad Jablonski <chad@jablonski.xyz> Reviewed-by: Chad Jablonski <chad@jablonski.xyz>
On Tue, 17 Mar 2026, Chad Jablonski wrote: > This works in the 24/32bpp case. Before this I see a yellow background in > fluxbox, after I see gray. > > I did notice that the existing big_endian_fb boolean in ati_vga_switch_mode > doesn't distinguish between big endian 32-bit and 16-bit swapping. In the 16bpp > case I see a black background in fluxbox. I did a quick and dirty test and > replaced the bswap32s with a 16-bit byte swap and then 16bpp displays the gray > background correctly. > > This is a pre-existing issue but I thought it was worth pointing out. That said > this fixes things for 24/32bpp and is an improvement. > > Tested-by: Chad Jablonski <chad@jablonski.xyz> > Reviewed-by: Chad Jablonski <chad@jablonski.xyz> Thanks for testing and review. Yes you're right I should have take into account bpp too. I'll have a look to see if I can fix this and send a new version. Regards, BALATON Zoltan
© 2016 - 2026 Red Hat, Inc.