# --- T2-COPYRIGHT-BEGIN --- # t2/package/*/xf86-video-rendition/04-overlapping-blits.patch # Copyright (C) 2026 The T2 SDE Project # SPDX-License-Identifier: GPL-2.0 or patched project license # --- T2-COPYRIGHT-END --- --- a/src/accelX.c 2026-07-12 13:25:59.391658596 +0200 +++ b/src/accelX.c @@ -184,8 +184,10 @@ /* screen to screen copy */ #if 1 - pXAAinfo->CopyAreaFlags=NO_TRANSPARENCY| - ONLY_TWO_BITBLT_DIRECTIONS; + /* RENDITIONSubsequentScreenToScreenCopy() derives the copy order from the + coordinates and splits overlapping copies itself, so every direction is + supported and XAA need not restrict itself to the two diagonal ones. */ + pXAAinfo->CopyAreaFlags=NO_TRANSPARENCY; pXAAinfo->SetupForScreenToScreenCopy= RENDITIONSetupForScreenToScreenCopy; pXAAinfo->SubsequentScreenToScreenCopy= @@ -545,33 +547,104 @@ pRendition->board.Rop=Rop2Rop[rop]; } +/* + * Issue a single CMD_SCREEN_BLT. The ucode has no argument for the copy + * direction, so this is only safe when source and destination do not overlap; + * RENDITIONSubsequentScreenToScreenCopy() guarantees that. + */ +static void +RENDITIONScreenBlt(ScrnInfoPtr pScreenInfo, + int srcX, int srcY, int dstX, int dstY, int w, int h) +{ + renditionPtr pRendition = RENDITIONPTR(pScreenInfo); + unsigned long iob = pRendition->board.io_base; + + if (w <= 0 || h <= 0) + return; + + waitfifo(5); + verite_out32(iob, CMD_SCREEN_BLT); + verite_out32(iob, pRendition->board.Rop); + verite_out32(iob, P2(srcX, srcY)); + verite_out32(iob, P2(w, h)); + verite_out32(iob, P2(dstX, dstY)); +} + void RENDITIONSubsequentScreenToScreenCopy(ScrnInfoPtr pScreenInfo, int srcX, int srcY, int dstX, int dstY, int w, int h) { - renditionPtr pRendition = RENDITIONPTR(pScreenInfo); - unsigned long iob = pRendition->board.io_base; - + int delta, band; #ifdef DEBUG ErrorF("RENDITION: RENDITIONSubsequentScreenToScreenCopy(" "%d, %d, %d, %d, %d, %d) called\n", srcX, srcY, dstX, dstY, w, h); #endif + if (w <= 0 || h <= 0) + return; -#if 1 /* def DEBUG */ - ErrorF("#ScreentoScreen# FIFO_INFREE 0x%x -- \n",verite_in8(iob+FIFOINFREE)); - ErrorF("#ScreentoScreen# FIFO_OUTVALID 0x%x -- \n",verite_in8(iob+FIFOOUTVALID)); -#endif + /* Disjoint rectangles: the copy order cannot matter. */ + if (srcX + w <= dstX || dstX + w <= srcX || + srcY + h <= dstY || dstY + h <= srcY) { + RENDITIONScreenBlt(pScreenInfo, srcX, srcY, dstX, dstY, w, h); + return; + } - waitfifo(5); - verite_out32(iob, CMD_SCREEN_BLT); - verite_out32(iob, pRendition->board.Rop); - verite_out32(iob, P2(srcX, srcY)); - verite_out32(iob, P2(w, h)); - verite_out32(iob, P2(dstX, dstY)); + /* The rectangles overlap and the blitter always copies forwards, so cut + the copy into pieces that are individually overlap-free and issue them + in an order that reads each piece before it gets overwritten. */ + + if (dstY > srcY) { + /* moving down: a band shorter than the vertical shift cannot overlap + itself, and copying from the bottom up leaves the rows we still + have to read untouched. */ + delta = dstY - srcY; + for (band = h; band > 0; band -= delta) { + int bh = (band < delta) ? band : delta; + RENDITIONScreenBlt(pScreenInfo, srcX, srcY + band - bh, + dstX, dstY + band - bh, w, bh); + } + } + else if (dstY < srcY) { + /* moving up: same argument, from the top down. */ + int off; + delta = srcY - dstY; + for (off = 0; off < h; off += delta) { + int bh = (h - off < delta) ? h - off : delta; + RENDITIONScreenBlt(pScreenInfo, srcX, srcY + off, + dstX, dstY + off, w, bh); + } + } + else if (dstX > srcX) { + /* pure horizontal shift to the right: columns instead of rows, + rightmost strip first. */ + delta = dstX - srcX; + for (band = w; band > 0; band -= delta) { + int bw = (band < delta) ? band : delta; + RENDITIONScreenBlt(pScreenInfo, srcX + band - bw, srcY, + dstX + band - bw, dstY, bw, h); + } + } + else if (dstX < srcX) { + /* pure horizontal shift to the left: leftmost strip first. */ + int off; + delta = srcX - dstX; + for (off = 0; off < w; off += delta) { + int bw = (w - off < delta) ? w - off : delta; + RENDITIONScreenBlt(pScreenInfo, srcX + off, srcY, + dstX + off, dstY, bw, h); + } + } + else { + /* Source and destination are the same rectangle. Every pixel is read + and written exactly once at the same address, so no write can clobber + a read that is still outstanding and a plain forward blit is safe for + any rop. */ + RENDITIONScreenBlt(pScreenInfo, srcX, srcY, dstX, dstY, w, h); + } }