Commit 9982c605 authored by BALATON Zoltan's avatar BALATON Zoltan Committed by Gerd Hoffmann
Browse files

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: default avatarBALATON Zoltan <balaton@eik.bme.hu>
Message-Id: <20200624164737.A941374633D@zero.eik.bme.hu>
Reviewed-by: default avatarPeter Maydell <peter.maydell@linaro.org>
Signed-off-by: default avatarGerd Hoffmann <kraxel@redhat.com>
parent d8327a68
Loading
Loading
Loading
Loading
+16 −10
Original line number Diff line number Diff line
@@ -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)) {