summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYang Zhao <yang@yangman.ca>2009-02-12 14:46:53 -0500
committerAlex Deucher <alexdeucher@gmail.com>2009-02-12 14:46:53 -0500
commite22cd4011b9be437ba89bff568e7fb82b4907d99 (patch)
tree0ef9ac90d4a400ac2c0d6914f2a83e135ea8b05e
parentda08b760bcf3d04d775c4440fafec10657bb1863 (diff)
R6xx/R7xx EXA: Further optimizations to overlapping copy
Diagonal overlapping copies can be reduced to either horizontal- or vertical-only offset, and the one with fewer copies is picked.
-rw-r--r--src/r600_exa.c103
1 files changed, 63 insertions, 40 deletions
diff --git a/src/r600_exa.c b/src/r600_exa.c
index 2cff645f..8a16b7a0 100644
--- a/src/r600_exa.c
+++ b/src/r600_exa.c
@@ -750,87 +750,110 @@ R600OverlapCopy(PixmapPtr pDst,
struct radeon_accel_state *accel_state = info->accel_state;
uint32_t dst_pitch = exaGetPixmapPitch(pDst) / (pDst->drawable.bitsPerPixel / 8);
uint32_t dst_offset = exaGetPixmapOffset(pDst) + info->fbLocation + pScrn->fbOffset;
- int i, chunk;
+ int i, hchunk, vchunk;
if (is_overlap(srcX, srcX + w, srcY, srcY + h,
dstX, dstX + w, dstY, dstY + h)) {
- /* Diagonally offset overlap is reduced to a horizontal-only offset by first
- * copying the vertically non-overlapping portion, then adjusting coordinates
+ /* Calculate height/width of non-overlapping area */
+ hchunk = (srcX < dstX) ? (dstX - srcX) : (srcX - dstX);
+ vchunk = (srcY < dstY) ? (dstY - srcY) : (srcY - dstY);
+
+ /* Diagonally offset overlap is reduced to either horizontal or vertical offset-only
+ * by copying a part of the non-overlapping portion, then adjusting coordinates
+ * Choose horizontal vs vertical to minimize the total number of copy operations
*/
- if (srcX != dstX) { // left/right or diagonal
- if (srcY > dstY ) { // diagonal up
- chunk = srcY - dstY;
- R600DoPrepareCopy(pScrn,
- dst_pitch, pDst->drawable.width, pDst->drawable.height, dst_offset, pDst->drawable.bitsPerPixel,
- dst_pitch, pDst->drawable.height, dst_offset, pDst->drawable.bitsPerPixel,
- accel_state->rop, accel_state->planemask);
- R600AppendCopyVertex(pScrn, srcX, srcY, dstX, dstY, w, chunk);
- R600DoCopy(pScrn);
-
- h = h - chunk;
- srcY = srcY + chunk;
- dstY = dstY + chunk;
- } else if (srcY < dstY) { // diagonal down
- chunk = dstY - srcY;
- R600DoPrepareCopy(pScrn,
- dst_pitch, pDst->drawable.width, pDst->drawable.height, dst_offset, pDst->drawable.bitsPerPixel,
- dst_pitch, pDst->drawable.height, dst_offset, pDst->drawable.bitsPerPixel,
- accel_state->rop, accel_state->planemask);
- R600AppendCopyVertex(pScrn, srcX, srcY + h - chunk, dstX, dstY + h - chunk, w, chunk);
- R600DoCopy(pScrn);
-
- h = h - chunk;
+ if (vchunk != 0 && hchunk != 0) { //diagonal
+ if ((w / hchunk) <= (h / vchunk)) { // reduce to horizontal
+ if (srcY > dstY ) { // diagonal up
+ R600DoPrepareCopy(pScrn,
+ dst_pitch, pDst->drawable.width, pDst->drawable.height, dst_offset, pDst->drawable.bitsPerPixel,
+ dst_pitch, pDst->drawable.height, dst_offset, pDst->drawable.bitsPerPixel,
+ accel_state->rop, accel_state->planemask);
+ R600AppendCopyVertex(pScrn, srcX, srcY, dstX, dstY, w, vchunk);
+ R600DoCopy(pScrn);
+
+ srcY = srcY + vchunk;
+ dstY = dstY + vchunk;
+ } else { // diagonal down
+ R600DoPrepareCopy(pScrn,
+ dst_pitch, pDst->drawable.width, pDst->drawable.height, dst_offset, pDst->drawable.bitsPerPixel,
+ dst_pitch, pDst->drawable.height, dst_offset, pDst->drawable.bitsPerPixel,
+ accel_state->rop, accel_state->planemask);
+ R600AppendCopyVertex(pScrn, srcX, srcY + h - vchunk, dstX, dstY + h - vchunk, w, vchunk);
+ R600DoCopy(pScrn);
+ }
+ h = h - vchunk;
+ vchunk = 0;
+ } else { //reduce to vertical
+ if (srcX > dstX ) { // diagonal left
+ R600DoPrepareCopy(pScrn,
+ dst_pitch, pDst->drawable.width, pDst->drawable.height, dst_offset, pDst->drawable.bitsPerPixel,
+ dst_pitch, pDst->drawable.height, dst_offset, pDst->drawable.bitsPerPixel,
+ accel_state->rop, accel_state->planemask);
+ R600AppendCopyVertex(pScrn, srcX, srcY, dstX, dstY, hchunk, h);
+ R600DoCopy(pScrn);
+
+ srcX = srcX + hchunk;
+ dstX = dstX + hchunk;
+ } else { // diagonal right
+ R600DoPrepareCopy(pScrn,
+ dst_pitch, pDst->drawable.width, pDst->drawable.height, dst_offset, pDst->drawable.bitsPerPixel,
+ dst_pitch, pDst->drawable.height, dst_offset, pDst->drawable.bitsPerPixel,
+ accel_state->rop, accel_state->planemask);
+ R600AppendCopyVertex(pScrn, srcX + w - hchunk, srcY, dstX + w - hchunk, dstY, hchunk, h);
+ R600DoCopy(pScrn);
+ }
+ w = w - hchunk;
+ hchunk = 0;
}
+ }
+ if (vchunk == 0) { // left/right
if (srcX < dstX) { // right
// copy right to left
- chunk = dstX - srcX;
- for (i = w; i > 0; i -= chunk) {
+ for (i = w; i > 0; i -= hchunk) {
R600DoPrepareCopy(pScrn,
dst_pitch, pDst->drawable.width, pDst->drawable.height, dst_offset, pDst->drawable.bitsPerPixel,
dst_pitch, pDst->drawable.height, dst_offset, pDst->drawable.bitsPerPixel,
accel_state->rop, accel_state->planemask);
- R600AppendCopyVertex(pScrn, srcX + i - chunk, srcY, dstX + i - chunk, dstY, chunk, h);
+ R600AppendCopyVertex(pScrn, srcX + i - hchunk, srcY, dstX + i - hchunk, dstY, hchunk, h);
R600DoCopy(pScrn);
}
} else { //left
// copy left to right
- chunk = srcX - dstX;
- for (i = 0; i < w; i += chunk) {
+ for (i = 0; i < w; i += hchunk) {
R600DoPrepareCopy(pScrn,
dst_pitch, pDst->drawable.width, pDst->drawable.height, dst_offset, pDst->drawable.bitsPerPixel,
dst_pitch, pDst->drawable.height, dst_offset, pDst->drawable.bitsPerPixel,
accel_state->rop, accel_state->planemask);
- R600AppendCopyVertex(pScrn, srcX + i, srcY, dstX + i, dstY, chunk, h);
+ R600AppendCopyVertex(pScrn, srcX + i, srcY, dstX + i, dstY, hchunk, h);
R600DoCopy(pScrn);
}
}
} else { //up/down
if (srcY > dstY) { // up
// copy top to bottom
- for (i = 0; i < h; i += chunk) {
- chunk = srcY - dstY;
+ for (i = 0; i < h; i += vchunk) {
R600DoPrepareCopy(pScrn,
dst_pitch, pDst->drawable.width, pDst->drawable.height, dst_offset, pDst->drawable.bitsPerPixel,
dst_pitch, pDst->drawable.height, dst_offset, pDst->drawable.bitsPerPixel,
accel_state->rop, accel_state->planemask);
- if (chunk > h - i) chunk = h - i;
- R600AppendCopyVertex(pScrn, srcX, srcY + i, dstX, dstY + i, w, chunk);
+ if (vchunk > h - i) vchunk = h - i;
+ R600AppendCopyVertex(pScrn, srcX, srcY + i, dstX, dstY + i, w, vchunk);
R600DoCopy(pScrn);
}
} else { // down
// copy bottom to top
- chunk = dstY - srcY;
- for (i = h; i > 0; i -= chunk) {
+ for (i = h; i > 0; i -= vchunk) {
R600DoPrepareCopy(pScrn,
dst_pitch, pDst->drawable.width, pDst->drawable.height, dst_offset, pDst->drawable.bitsPerPixel,
dst_pitch, pDst->drawable.height, dst_offset, pDst->drawable.bitsPerPixel,
accel_state->rop, accel_state->planemask);
- if (chunk > i) chunk = i;
- R600AppendCopyVertex(pScrn, srcX, srcY + i - chunk, dstX, dstY + i - chunk, w, chunk);
+ if (vchunk > i) vchunk = i;
+ R600AppendCopyVertex(pScrn, srcX, srcY + i - vchunk, dstX, dstY + i - vchunk, w, vchunk);
R600DoCopy(pScrn);
}
}