Implement flushing the 128-bit HOST_DATA accumulator to VRAM to enable text rendering in X. Currently supports only the monochrome foreground/background datatype.
The flush is broken up into two steps. First, expansion of the monochrome bits to the destination color depth. Then the expanded pixels are sent to the ati_2d_do_blt one scanline at a time. ati_2d_do_blt then clips and performs the blit. Signed-off-by: Chad Jablonski <[email protected]> --- hw/display/ati.c | 4 +- hw/display/ati_2d.c | 85 ++++++++++++++++++++++++++++++++++++++++++- hw/display/ati_int.h | 3 ++ hw/display/ati_regs.h | 4 ++ 4 files changed, 93 insertions(+), 3 deletions(-) diff --git a/hw/display/ati.c b/hw/display/ati.c index e6868ddb8b..aa13c25f59 100644 --- a/hw/display/ati.c +++ b/hw/display/ati.c @@ -1052,13 +1052,13 @@ static void ati_mm_write(void *opaque, hwaddr addr, case HOST_DATA7: s->host_data.acc[s->host_data.next++] = data; if (s->host_data.next >= 4) { - qemu_log_mask(LOG_UNIMP, "HOST_DATA flush not yet implemented\n"); + ati_flush_host_data(s); s->host_data.next = 0; } break; case HOST_DATA_LAST: s->host_data.acc[s->host_data.next] = data; - qemu_log_mask(LOG_UNIMP, "HOST_DATA flush not yet implemented\n"); + ati_flush_host_data(s); ati_host_data_reset(&s->host_data); break; default: diff --git a/hw/display/ati_2d.c b/hw/display/ati_2d.c index a5dc5ba98e..5a0e918810 100644 --- a/hw/display/ati_2d.c +++ b/hw/display/ati_2d.c @@ -274,6 +274,12 @@ void ati_2d_blt(ATIVGAState *s) uint8_t *end = s->vga.vram_ptr + s->vga.vram_size; ATIBltDst dst; ATIBltSrc src; + uint32_t src_source = s->regs.dp_mix & DP_SRC_SOURCE; + + if (src_source == DP_SRC_HOST || src_source == DP_SRC_HOST_BYTEALIGN) { + /* HOST_DATA sources are handled by ati_flush_host_data() */ + return; + } setup_2d_blt_dst(s, &dst); @@ -290,7 +296,6 @@ void ati_2d_blt(ATIVGAState *s) src.bits += s->regs.crtc_offset & 0x07ffffff; src.stride *= dst.bpp; } - if (src.x > 0x3fff || src.y > 0x3fff || src.bits >= end || src.bits + src.x + (src.y + dst.rect.height) * src.stride >= end) { @@ -300,3 +305,81 @@ void ati_2d_blt(ATIVGAState *s) ati_2d_do_blt(s, &src, &dst); } + +void ati_flush_host_data(ATIVGAState *s) +{ + ATIBltDst dst, chunk; + ATIBltSrc src; + uint32_t fg, bg; + unsigned bypp, 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; + + if ((s->regs.dp_mix & DP_SRC_SOURCE) != DP_SRC_HOST) { + qemu_log_mask(LOG_UNIMP, "host_data_blt: only DP_SRC_HOST supported\n"); + return; + } + if ((s->regs.dp_datatype & DP_SRC_DATATYPE) != SRC_MONO_FRGD_BKGD) { + qemu_log_mask(LOG_UNIMP, + "host_data_blt: only SRC_MONO_FRGD_BKGD supported\n"); + return; + } + + setup_2d_blt_dst(s, &dst); + + if (!dst.left_to_right || !dst.top_to_bottom) { + qemu_log_mask(LOG_UNIMP, "host_data_blt: only L->R, T->B supported\n"); + return; + } + + fg = s->regs.dp_src_frgd_clr; + bg = s->regs.dp_src_bkgd_clr; + bypp = dst.bpp / 8; + + /* Expand monochrome bits to color pixels */ + 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++) { + int bit = byte_pix_order ? i : (7 - i); + bool is_fg = extract8(byte_val, bit, 1); + uint32_t color = is_fg ? fg : bg; + stn_he_p(&pix_buf[idx * bypp], bypp, color); + idx += 1; + } + } + } + + /* Set up source to point at pix_buf (treated as a single row) */ + src.bits = pix_buf; + src.y = 0; + src.stride = ATI_HOST_DATA_ACC_BITS * bypp; + + /* Copy to VRAM one scanline chunk at a time */ + row = s->host_data.row; + col = s->host_data.col; + idx = 0; + chunk = dst; + while (idx < ATI_HOST_DATA_ACC_BITS && row < dst.rect.height) { + unsigned pix_in_scanline = MIN(ATI_HOST_DATA_ACC_BITS - idx, + dst.rect.width - col); + src.x = idx; + /* Build a rect for this scanline chunk */ + qemu_rect_init(&chunk.rect, + dst.rect.x + col, + dst.rect.y + row, + pix_in_scanline, 1); + ati_2d_do_blt(s, &src, &chunk); + idx += pix_in_scanline; + col += pix_in_scanline; + if (col >= dst.rect.width) { + col = 0; + row += 1; + } + } + + /* Track state of the overall blit for use by the next flush */ + s->host_data.row = row; + s->host_data.col = col; +} diff --git a/hw/display/ati_int.h b/hw/display/ati_int.h index 38725c57fa..ff7148a71a 100644 --- a/hw/display/ati_int.h +++ b/hw/display/ati_int.h @@ -29,6 +29,8 @@ /* Radeon RV100 (VE) */ #define PCI_DEVICE_ID_ATI_RADEON_QY 0x5159 +#define ATI_HOST_DATA_ACC_BITS 128 + #define TYPE_ATI_VGA "ati-vga" OBJECT_DECLARE_SIMPLE_TYPE(ATIVGAState, ATI_VGA) @@ -120,5 +122,6 @@ struct ATIVGAState { const char *ati_reg_name(int num); void ati_2d_blt(ATIVGAState *s); +void ati_flush_host_data(ATIVGAState *s); #endif /* ATI_INT_H */ diff --git a/hw/display/ati_regs.h b/hw/display/ati_regs.h index 48f15e9b1d..9d08d3e956 100644 --- a/hw/display/ati_regs.h +++ b/hw/display/ati_regs.h @@ -397,7 +397,11 @@ #define DST_32BPP 0x00000006 #define DP_DST_DATATYPE 0x0000000f #define DP_BRUSH_DATATYPE 0x00000f00 +#define SRC_MONO_FRGD_BKGD 0x00000000 +#define SRC_MONO_FRGD 0x00010000 +#define SRC_COLOR 0x00020000 #define DP_SRC_DATATYPE 0x00030000 +#define DP_BYTE_PIX_ORDER 0x40000000 #define BRUSH_SOLIDCOLOR 0x00000d00 -- 2.51.2
