Use scissor registers to clip blit operations. This is required for text rendering in X using the r128 driver. Without it overly-wide glyphs are drawn and create all sorts of chaos.
The visible destination rectangle (vis_dst) is the intersection of the scissor rectangle and the destination rectangle (dst.rect). The src also needs to be offset if clipped on the top and/or left sides to ensure that src data is read correctly and appears clipped when drawn rather than shifted. Signed-off-by: Chad Jablonski <[email protected]> --- hw/display/ati_2d.c | 81 ++++++++++++++++++++++++++++----------------- 1 file changed, 50 insertions(+), 31 deletions(-) diff --git a/hw/display/ati_2d.c b/hw/display/ati_2d.c index 691e0f0702..a5dc5ba98e 100644 --- a/hw/display/ati_2d.c +++ b/hw/display/ati_2d.c @@ -86,7 +86,8 @@ static void ati_2d_do_blt(ATIVGAState *s, const ATIBltSrc *src, ATIBltDst *dst) /* rewritten but for now as a start just to get some output: */ DisplaySurface *ds = qemu_console_surface(s->vga.con); uint8_t *end = s->vga.vram_ptr + s->vga.vram_size; - int dst_stride_words, src_stride_words; + int dst_stride_words, src_stride_words, vis_src_x, vis_src_y; + QemuRect scissor, vis_dst; DPRINTF("%p %u ds: %p %d %d rop: %x\n", s->vga.vram_ptr, s->vga.vbe_start_addr, surface_data(ds), surface_stride(ds), @@ -108,14 +109,32 @@ static void ati_2d_do_blt(ATIVGAState *s, const ATIBltSrc *src, ATIBltDst *dst) return; } + qemu_rect_init(&scissor, + s->regs.sc_left, s->regs.sc_top, + s->regs.sc_right - s->regs.sc_left + 1, + s->regs.sc_bottom - s->regs.sc_top + 1); + qemu_rect_intersect(&dst->rect, &scissor, &vis_dst); + if (!vis_dst.height || !vis_dst.width) { + /* Nothing to do, completely clipped */ + return; + } + dst_stride_words = dst->stride / sizeof(uint32_t); src_stride_words = src->stride / sizeof(uint32_t); + /* + * The src must be offset if clipping is applied to the dst. + * This is so that when the source is blit to a dst clipped + * on the top or left the src image is not shifted into the + * clipped region but actually clipped. + */ + vis_src_x = src->x + (vis_dst.x - dst->rect.x); + vis_src_y = src->y + (vis_dst.y - dst->rect.y); DPRINTF("%d %d %d, %d %d %d, (%d,%d) -> (%d,%d) %dx%d %c %c\n", s->regs.src_offset, s->regs.dst_offset, s->regs.default_offset, src->stride, dst->stride, s->regs.default_pitch, - src->x, src->y, dst->rect.x, dst->rect.y, - dst->rect.width, dst->rect.height, + vis_src_x, vis_src_y, vis_dst.x, vis_dst.y, + vis_dst.width, vis_dst.height, (dst->left_to_right ? '>' : '<'), (dst->top_to_bottom ? 'v' : '^')); @@ -133,33 +152,33 @@ static void ati_2d_do_blt(ATIVGAState *s, const ATIBltSrc *src, ATIBltDst *dst) src->bits, dst->bits, src_stride_words, dst_stride_words, dst->bpp, dst->bpp, - src->x, src->y, dst->rect.x, dst->rect.y, - dst->rect.width, dst->rect.height); + vis_src_x, vis_src_y, vis_dst.x, vis_dst.y, + vis_dst.width, vis_dst.height); #ifdef CONFIG_PIXMAN if ((s->use_pixman & BIT(1)) && dst->left_to_right && dst->top_to_bottom) { fallback = !pixman_blt((uint32_t *)src->bits, (uint32_t *)dst->bits, src_stride_words, dst_stride_words, dst->bpp, dst->bpp, - src->x, src->y, dst->rect.x, dst->rect.y, - dst->rect.width, dst->rect.height); + vis_src_x, vis_src_y, vis_dst.x, vis_dst.y, + vis_dst.width, vis_dst.height); } else if (s->use_pixman & BIT(1)) { /* FIXME: We only really need a temporary if src and dst overlap */ - int llb = dst->rect.width * (dst->bpp / 8); + int llb = vis_dst.width * (dst->bpp / 8); int tmp_stride = DIV_ROUND_UP(llb, sizeof(uint32_t)); uint32_t *tmp = g_malloc(tmp_stride * sizeof(uint32_t) * - dst->rect.height); + vis_dst.height); fallback = !pixman_blt((uint32_t *)src->bits, tmp, src_stride_words, tmp_stride, dst->bpp, dst->bpp, - src->x, src->y, 0, 0, - dst->rect.width, dst->rect.height); + vis_src_x, vis_src_y, 0, 0, + vis_dst.width, vis_dst.height); if (!fallback) { fallback = !pixman_blt(tmp, (uint32_t *)dst->bits, tmp_stride, dst_stride_words, dst->bpp, dst->bpp, - 0, 0, dst->rect.x, dst->rect.y, - dst->rect.width, dst->rect.height); + 0, 0, vis_dst.x, vis_dst.y, + vis_dst.width, vis_dst.height); } g_free(tmp); } else @@ -169,17 +188,17 @@ static void ati_2d_do_blt(ATIVGAState *s, const ATIBltSrc *src, ATIBltDst *dst) } if (fallback) { unsigned int y, i, j, bypp = dst->bpp / 8; - for (y = 0; y < dst->rect.height; y++) { - i = dst->rect.x * bypp; - j = src->x * bypp; + for (y = 0; y < vis_dst.height; y++) { + i = vis_dst.x * bypp; + j = vis_src_x * bypp; if (dst->top_to_bottom) { - i += (dst->rect.y + y) * dst->stride; - j += (src->y + y) * src->stride; + i += (vis_dst.y + y) * dst->stride; + j += (vis_src_y + y) * src->stride; } else { - i += (dst->rect.y + dst->rect.height - 1 - y) * dst->stride; - j += (src->y + dst->rect.height - 1 - y) * src->stride; + i += (vis_dst.y + vis_dst.height - 1 - y) * dst->stride; + j += (vis_src_y + vis_dst.height - 1 - y) * src->stride; } - memmove(&dst->bits[i], &src->bits[j], dst->rect.width * bypp); + memmove(&dst->bits[i], &src->bits[j], vis_dst.width * bypp); } } break; @@ -205,20 +224,20 @@ static void ati_2d_do_blt(ATIVGAState *s, const ATIBltSrc *src, ATIBltDst *dst) } DPRINTF("pixman_fill(%p, %d, %d, %d, %d, %d, %d, %x)\n", - dst->bits, dst_stride_words, dst->bpp, dst->rect.x, dst->rect.y, - dst->rect.width, dst->rect.height, filler); + dst->bits, dst_stride_words, dst->bpp, vis_dst.x, vis_dst.y, + vis_dst.width, vis_dst.height, filler); #ifdef CONFIG_PIXMAN if (!(s->use_pixman & BIT(0)) || !pixman_fill((uint32_t *)dst->bits, - dst_stride_words, dst->bpp, dst->rect.x, dst->rect.y, - dst->rect.width, dst->rect.height, filler)) + dst_stride_words, dst->bpp, vis_dst.x, vis_dst.y, + vis_dst.width, vis_dst.height, filler)) #endif { /* fallback when pixman failed or we don't want to call it */ unsigned int x, y, i, bypp = dst->bpp / 8; - for (y = 0; y < dst->rect.height; y++) { - i = dst->rect.x * bypp + (dst->rect.y + y) * dst->stride; - for (x = 0; x < dst->rect.width; x++, i += bypp) { + for (y = 0; y < vis_dst.height; y++) { + i = vis_dst.x * bypp + (vis_dst.y + y) * dst->stride; + for (x = 0; x < vis_dst.width; x++, i += bypp) { stn_he_p(&dst->bits[i], bypp, filler); } } @@ -237,7 +256,7 @@ static void ati_2d_do_blt(ATIVGAState *s, const ATIBltSrc *src, ATIBltDst *dst) * This has not yet been validated on R100 hardware. */ s->regs.dst_y = (dst->top_to_bottom ? - dst->rect.y + dst->rect.height : dst->rect.y); + vis_dst.y + vis_dst.height : vis_dst.y); } if (dst->bits >= s->vga.vram_ptr + s->vga.vbe_start_addr && @@ -245,8 +264,8 @@ static void ati_2d_do_blt(ATIVGAState *s, const ATIBltSrc *src, ATIBltDst *dst) s->vga.vbe_regs[VBE_DISPI_INDEX_YRES] * s->vga.vbe_line_offset) { memory_region_set_dirty(&s->vga.vram, s->vga.vbe_start_addr + s->regs.dst_offset + - dst->rect.y * surface_stride(ds), - dst->rect.height * surface_stride(ds)); + vis_dst.y * surface_stride(ds), + vis_dst.height * surface_stride(ds)); } } -- 2.51.2
