From 9982c605a71bffd4c52c111b5c79e2060953a762 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Wed, 24 Jun 2020 18:42:18 +0200 Subject: sm501: Fix and optimize overlap check When doing reverse blit we need to check if source and dest overlap but it is not trivial due to possible different base and pitch of source and dest. Do rectangle overlap if base and pitch match, otherwise just check if memory area containing the rects overlaps so rects could possibly overlap. Signed-off-by: BALATON Zoltan Message-Id: <20200624164737.A941374633D@zero.eik.bme.hu> Reviewed-by: Peter Maydell Signed-off-by: Gerd Hoffmann --- hw/display/sm501.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/hw/display/sm501.c b/hw/display/sm501.c index 2db347d..9cccc68 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -690,6 +690,7 @@ static void sm501_2d_operation(SM501State *s) unsigned int dst_pitch = (s->twoD_pitch >> 16) & 0x1FFF; int crt = (s->dc_crt_control & SM501_DC_CRT_CONTROL_SEL) ? 1 : 0; int fb_len = get_width(s, crt) * get_height(s, crt) * get_bpp(s, crt); + bool overlap = false; if ((s->twoD_stretch >> 16) & 0xF) { qemu_log_mask(LOG_UNIMP, "sm501: only XY addressing is supported.\n"); @@ -784,16 +785,21 @@ static void sm501_2d_operation(SM501State *s) ldn_he_p(&s->local_mem[src_base + si], bypp)); break; } - /* Check for overlaps, this could be made more exact */ - uint32_t sb, se, db, de; - sb = src_base + src_x + src_y * (width + src_pitch); - se = sb + width + height * (width + src_pitch); - db = dst_base + dst_x + dst_y * (width + dst_pitch); - de = db + width + height * (width + dst_pitch); - if (rtl && ((db >= sb && db <= se) || (de >= sb && de <= se))) { - /* regions may overlap: copy via temporary */ - int llb = width * bypp; - int tmp_stride = DIV_ROUND_UP(llb, sizeof(uint32_t)); + /* If reverse blit do simple check for overlaps */ + if (rtl && src_base == dst_base && src_pitch == dst_pitch) { + overlap = (src_x < dst_x + width && src_x + width > dst_x && + src_y < dst_y + height && src_y + height > dst_y); + } else if (rtl) { + unsigned int sb, se, db, de; + sb = src_base + (src_x + src_y * src_pitch) * bypp; + se = sb + (width + (height - 1) * src_pitch) * bypp; + db = dst_base + (dst_x + dst_y * dst_pitch) * bypp; + de = db + (width + (height - 1) * dst_pitch) * bypp; + overlap = (db < se && sb < de); + } + if (overlap) { + /* pixman can't do reverse blit: copy via temporary */ + int tmp_stride = DIV_ROUND_UP(width * bypp, sizeof(uint32_t)); uint32_t *tmp = tmp_buf; if (tmp_stride * sizeof(uint32_t) * height > sizeof(tmp_buf)) { -- cgit v1.1