BitBltImpl.mesa
Copyright (C) 1986 by Xerox Corporation. All rights reserved.
Willie-Sue, September 12, 1986 2:50:40 pm PDT
Carl Hauser, November 12, 1986 2:31:12 pm PST
DIRECTORY
Basics,
DragOps,
DragOpsUtils,
BitBlt;
DragonBitBltImpl:
MONITOR
EXPORTS BitBlt
= BEGIN
BitAddress: TYPE = BitBlt.DragonBitAddress;
DragonPointer: TYPE = BitBlt.DragonPointer;
bitsPerWord: CARDINAL = Basics.bitsPerWord;
BitBltInc: TYPE = RECORD[wVal, bitVal: INT, easy: BOOL]; -- easy if value MOD bitsPerWord = 0
srcAddr: BitAddress; -- address of source word at beginning of line
dstAddr: BitAddress; -- address of destination word at beginning of line
srcFunc: BitBlt.SrcFunc ← null;
dstFunc: BitBlt.DstFunc ← null;
srcInc, dstInc: BitBltInc;
goingForward: BOOL ← TRUE;
MaskArray: ARRAY [0..bitsPerWord] OF DragOps.Word;
isThin: BOOL ← FALSE; -- true if dest is all within one word
lMask: DragOps.Word;
rMask: DragOps.Word;
skew: DragOps.SixBitIndex;
dWidth, sWidth:
INT;
-- width in words, including left & right partial words
dWidth & sWidth differ by ar most +/-1
dWidth > 2 => left partial, dWidth-2 full words, and right partial
dWidth = 2 => left partial, right partial only
dWidth = 1 => entire destination within one word - special case as both masks need to be applied at the same time
extraWordAtLeft, extraWordAtRight:
BOOL;
If sWidth = dWidth+1, an extra source word must be fetched at both ends.
If sWidth = dWidth-1 or sWidth = 1, no extra source words need be fetched.
If sWidth = dWidth # 1, an extra source word must be fetched at one end:
if src.bit mod bitsPerWord > dst.bit mod bitsPerWord then left else right
isGray: BOOL ← FALSE;
grayParam: BitBlt.GrayParm;
grayWidth: BitBltInc;
grayBump: BitBltInc;
lastGray: [0..15);
InvalidBitBltCall: ERROR = CODE;
BITBLT: PUBLIC ENTRY PROC[bbt: DragonBitBlt.BitBltTablePtr] = {
BITBLT:
PUBLIC
PROC[bbt: BitBlt.BitBltTablePtr] = {
ENABLE UNWIND, ABORTED => NULL;
grayHeightMod: INT;
lineNum: INT ← DoSetup[bbt]; -- which line do we start with
IF isGray THEN grayHeightMod ← grayParam.heightMinusOne+1;
WHILE lineNum
IN [0..bbt.height)
DO
sInc: BitBltInc;
IF isGray
THEN BltOneLineForwardGray[]
ELSE IF goingForward THEN BltOneLineForward[] ELSE BltOneLineBackward[];
lineNum ← lineNum + (IF goingForward THEN 1 ELSE -1);
sInc ←
IF bbt.flags.gray
THEN
IF (lineNum MOD grayHeightMod) = lastGray THEN grayBump ELSE grayWidth
ELSE srcInc;
IF sInc.easy
AND dstInc.easy
THEN {
srcAddr ← BitAddrInc[srcAddr, sInc];
dstAddr ← BitAddrInc[dstAddr, dstInc];
}
ELSE Recompute[bbt, sInc];
ENDLOOP;
};
DoSetup:
PROC[bbt: BitBlt.BitBltTablePtr]
RETURNS[lineNum:
INT] = {
check for legality
IF bbt.flags.reserved # 0 OR bbt.reserved # 0 OR
bbt.src.reserved # 0 OR bbt.dst.reserved # 0 OR
(~bbt.flags.gray AND LOOPHOLE[bbt.srcDesc, INTEGER] = 0) OR -- bbt.dstBpl = 0 OR
bbt.width > LAST[NAT] OR bbt.height > LAST[NAT] THEN ERROR InvalidBitBltCall;
goingForward ← bbt.flags.direction = forward;
srcFunc ← bbt.flags.srcFunc;
dstFunc ← bbt.flags.dstFunc;
srcAddr ← bbt.src; -- true for either real source or gray
IF (isGray ← bbt.flags.gray)
THEN {
grayParam ← LOOPHOLE[bbt.srcDesc];
more checking
IF grayParam.widthMinusOne # 0
OR grayParam.reserved # 0
OR
~goingForward OR ~bbt.flags.disjoint OR bbt.dstBpl < 0 THEN ERROR InvalidBitBltCall;
grayWidth.easy ← TRUE;
grayWidth.wVal ← grayParam.widthMinusOne+1;
grayWidth.bitVal ← grayWidth.wVal * bitsPerWord;
grayBump.easy ← TRUE;
grayBump.wVal ← -grayWidth.wVal*grayParam.heightMinusOne;
grayBump.bitVal ← grayBump.wVal * bitsPerWord;
}
ELSE {
srcI: INT = LOOPHOLE[bbt.srcDesc];
IF srcI < 0
THEN srcInc.easy ← (-srcI
MOD bitsPerWord) = 0
ELSE srcInc.easy ← (srcI MOD bitsPerWord) = 0;
srcInc.wVal ← IF srcInc.easy THEN srcI/bitsPerWord ELSE -1;
srcInc.bitVal ← srcI;
IF (goingForward
AND (srcInc.bitVal < 0
OR bbt.dstBpl < 0))
OR
(~goingForward
AND (srcInc.bitVal > 0
OR bbt.dstBpl > 0))
THEN
ERROR InvalidBitBltCall;
};
IF bbt.dstBpl < 0
THEN dstInc.easy ← (-bbt.dstBpl
MOD bitsPerWord) = 0
ELSE dstInc.easy ← (bbt.dstBpl MOD bitsPerWord) = 0;
dstInc.bitVal ← bbt.dstBpl;
dstInc.wVal ← IF dstInc.easy THEN bbt.dstBpl/bitsPerWord ELSE -1;
IF isGray
THEN lastGray ←
IF goingForward
THEN
grayParam.heightMinusOne - grayParam.yOffset
ELSE grayParam.yOffset;
lineNum ← IF goingForward THEN 0 ELSE bbt.height-1;
checking for thin case, setting up masks, widths for line
BEGIN
bitSkew: INT = srcAddr.bit - dstAddr.bit;
finalDstInFirstLine: BitAddress ←
BitAddrInc[bbt.dst, [wVal: -1, bitVal: bbt.width, easy: FALSE] ];
lMask ← MaskArray[dstAddr.bit];
rMask ← RMask[finalDstInFirstLine.bit];
skew ← IF bitSkew < 0 THEN bitsPerWord + bitSkew ELSE bitSkew;
dWidth ← (dstAddr.bit + bbt.width + bitsPerWord - 1)/bitsPerWord;
sWidth ← (srcAddr.bit + bbt.width + bitsPerWord - 1)/bitsPerWord;
isThin ← (dWidth = 1);
extraWordAtLeft ← extraWordAtRight ← FALSE;
SELECT
TRUE
FROM
sWidth > dWidth => extraWordAtLeft ← extraWordAtRight ← TRUE;
sWidth < dWidth, sWidth = 1 => NULL;
ENDCASE =>
IF bitSkew >= 0
THEN extraWordAtLeft ←
TRUE
ELSE extraWordAtRight ← TRUE;
END;
};
BitAddrInc:
PROC[base: BitAddress, offset: BitBltInc]
RETURNS[ba: BitAddress] =
TRUSTED {
IF offset.easy
THEN {
ba.word ← LOOPHOLE[offset.wVal + LOOPHOLE[base.word, INT], DragonPointer];
ba.bit ← base.bit;
}
ELSE {
addedBits: INT = offset.bitVal + base.bit;
absBits: INT = IF addedBits < 0 THEN -addedBits ELSE addedBits;
wordPart: INT ← IntShiftRight[absBits, DragOps.logBitsPerWord];
wordPart: INT ← IntShiftRight[absBits, 5]; -- DragOps.logBitsPerWord is wrong
IF addedBits < 0 THEN wordPart ← - wordPart;
ba.word ← LOOPHOLE[LOOPHOLE[base.word, INT] + wordPart, DragonPointer];
ba.bit ← IntAnd[addedBits, bitsPerWord-1];
};
};
IntShiftRight:
PROC[x:
INT, dist: DragOps.SixBitIndex]
RETURNS [
INT] =
TRUSTED
INLINE {
OPEN Basics;
RETURN [LOOPHOLE[ Basics.ShiftRight[LOOPHOLE[x, LongNumber], dist], INT] ];
};
IntAnd:
PROC[x, y:
INT]
RETURNS [
INT] =
TRUSTED
INLINE {
OPEN Basics;
RETURN [
LOOPHOLE[ Basics.BITAND[LOOPHOLE[x], LOOPHOLE[y]], INT] ];
};
Recompute:
PROC[bbt: BitBlt.BitBltTablePtr, sInc: BitBltInc] = {
either srcBpl or dstBpl was not a multiple of bitsPerWord; recompute masks for this line
bitSkew: INT;
finalDstAddrInLine: BitAddress;
srcAddr ← BitAddrInc[srcAddr, [wVal: sInc.wVal, bitVal: sInc.bitVal, easy: sInc.easy] ];
dstAddr ← BitAddrInc[dstAddr, [wVal: dstInc.wVal, bitVal: dstInc.bitVal, easy: dstInc.easy] ];
bitSkew ← srcAddr.bit - dstAddr.bit;
skew ← IF bitSkew < 0 THEN bitsPerWord + bitSkew ELSE bitSkew;
finalDstAddrInLine ← BitAddrInc[dstAddr, [wVal: -1, bitVal: bbt.width, easy: FALSE] ];
lMask ← MaskArray[dstAddr.bit];
rMask ← RMask[finalDstAddrInLine.bit];
dWidth ← (dstAddr.bit + bbt.width + bitsPerWord - 1)/bitsPerWord;
sWidth ← (srcAddr.bit + bbt.width + bitsPerWord - 1)/bitsPerWord;
isThin ← dWidth = 1;
extraWordAtLeft ← extraWordAtRight ← FALSE;
SELECT
TRUE
FROM
sWidth > dWidth => extraWordAtLeft ← extraWordAtRight ← TRUE;
sWidth < dWidth, sWidth = 1 => NULL;
ENDCASE =>
IF bitSkew >= 0
THEN extraWordAtLeft ←
TRUE
ELSE extraWordAtRight ← TRUE;
};
BltOneLineForward:
PROC =
TRUSTED {
src: DragonPointer ← srcAddr.word;
dst: DragonPointer ← dstAddr.word;
longSrcHi, longSrcLo: DragOps.Word;
dstValue, srcWord, curVal: DragOps.Word;
width: INT ← dWidth;
longSrcHi ← longSrcLo ← FetchWord[src];
src ← LOOPHOLE[src+1];
IF extraWordAtLeft
THEN {
longSrcLo ← FetchWord[src];
src ← LOOPHOLE[src+1];
};
[srcWord, dstValue] ← ComputeDstValue[longSrcHi, longSrcLo, dst];
IF isThin
THEN {
doubleMask: DragOps.Word = Basics.BITAND[lMask, rMask];
curVal ← Basics.BITAND[FetchWord[dst], Basics.BITNOT[doubleMask]];
dstValue ← Basics.BITAND[dstValue, doubleMask];
dst^ ← Basics.BITOR[curVal, dstValue];
StoreWord[dst, Basics.BITOR[curVal, dstValue] ];
RETURN;
};
dstValue ← Basics.BITAND[dstValue, lMask]; -- at left side, so do left mask
curVal ← Basics.BITAND[FetchWord[dst], Basics.BITNOT[lMask]];
dstValue ← Basics.BITOR[curVal, dstValue];
DO
-- store full words in this loop
StoreWord[dst, dstValue];
dst ← LOOPHOLE[dst + 1];
longSrcHi ← longSrcLo; -- (lshift bitsPerWord)
IF width <=2 THEN EXIT;
longSrcLo ← FetchWord[src];
[srcWord, dstValue] ← ComputeDstValue[longSrcHi, longSrcLo, dst];
src ← LOOPHOLE[src+1];
width ← width - 1;
ENDLOOP;
IF extraWordAtRight THEN longSrcLo ← FetchWord[src];
[srcWord, dstValue] ← ComputeDstValue[longSrcHi, longSrcLo, dst];
curVal ← Basics.BITAND[FetchWord[dst], Basics.BITNOT[rMask] ];
dstValue ← Basics.BITAND[dstValue, rMask]; -- at right side, so do right mask
StoreWord[dst, Basics.BITOR[curVal, dstValue] ];
};
BltOneLineForwardGray:
PROC =
TRUSTED {
src: DragonPointer ← srcAddr.word;
dst: DragonPointer ← dstAddr.word;
longSrcHi, longSrcLo: DragOps.Word;
dstValue, srcWord, curVal: DragOps.Word;
width: INT ← dWidth;
count: INT ← 0;
longSrcHi ← longSrcLo ← FetchWord[src];
src ← GrayInc[src, count ← count + 1];
IF extraWordAtLeft
THEN {
longSrcLo ← FetchWord[src];
src ← GrayInc[src, count ← count + 1];
};
[srcWord, dstValue] ← ComputeDstValue[longSrcHi, longSrcLo, dst];
IF isThin
THEN {
doubleMask: DragOps.Word = Basics.BITAND[lMask, rMask];
curVal ← Basics.BITAND[FetchWord[dst], Basics.BITNOT[doubleMask]];
dstValue ← Basics.BITAND[dstValue, doubleMask];
StoreWord[dst, Basics.BITOR[curVal, dstValue]];
RETURN;
};
dstValue ← Basics.BITAND[dstValue, lMask]; -- at left side, do left mask
curVal ← Basics.BITAND[FetchWord[dst], Basics.BITNOT[lMask]];
dstValue ← Basics.BITOR[curVal, dstValue];
DO
-- store full words in this loop
StoreWord[dst, dstValue];
dst ← LOOPHOLE[dst + 1];
longSrcHi ← longSrcLo;
IF width <=2 THEN EXIT;
longSrcLo ← FetchWord[src];
[srcWord, dstValue] ← ComputeDstValue[longSrcHi, longSrcLo, dst];
src ← GrayInc[src, count ← count + 1];
width ← width - 1;
ENDLOOP;
IF extraWordAtRight THEN longSrcLo ← FetchWord[src];
[srcWord, dstValue] ← ComputeDstValue[longSrcHi, longSrcLo, dst];
curVal ← Basics.BITAND[FetchWord[dst], Basics.BITNOT[rMask] ];
dstValue ← Basics.BITAND[dstValue, rMask]; -- at right side, so do right mask
StoreWord[dst, Basics.BITOR[curVal, dstValue]];
};
BltOneLineBackward:
PROC =
TRUSTED {
src: DragonPointer ← LOOPHOLE[srcAddr.word + sWidth - 1];
dst: DragonPointer ← LOOPHOLE[dstAddr.word + dWidth - 1];
longSrcHi, longSrcLo: DragOps.Word;
dstValue, srcWord, curVal: DragOps.Word;
width: INTEGER ← dWidth;
longSrcHi ← longSrcLo ← FetchWord[src];
src ←
LOOPHOLE[src-1];
IF extraWordAtRight THEN {
longSrcHi ← FetchWord[src];
src ← LOOPHOLE[src-1];
};
[srcWord, dstValue] ← ComputeDstValue[longSrcHi, longSrcLo, dst];
IF isThin
THEN {
doubleMask: DragOps.Word = Basics.BITAND[lMask, rMask];
curVal ← Basics.BITAND[FetchWord[dst], Basics.BITNOT[doubleMask]];
dstValue ← Basics.BITAND[dstValue, doubleMask];
StoreWord[dst, Basics.BITOR[curVal, dstValue]];
RETURN;
};
dstValue ← Basics.BITAND[dstValue, rMask]; -- at right side, do right mask
curVal ← Basics.BITAND[FetchWord[dst], Basics.BITNOT[rMask] ];
dstValue ← Basics.BITOR[curVal, dstValue];
DO
-- store full words in this loop
StoreWord[dst, dstValue];
dst ← LOOPHOLE[dst-1];
longSrcLo ← longSrcHi; -- cheaper than shifting
IF width <=2 THEN EXIT;
longSrcHi ← FetchWord[src];
src ← LOOPHOLE[src-1];
[srcWord, dstValue] ← ComputeDstValue[longSrcHi, longSrcLo, dst];
width ← width - 1;
ENDLOOP;
IF extraWordAtLeft THEN longSrcHi ← FetchWord[src];
[srcWord, dstValue] ← ComputeDstValue[longSrcHi, longSrcLo, dst];
dstValue ← Basics.BITAND[dstValue, lMask]; -- at left side, so do left mask
curVal ← Basics.BITAND[FetchWord[dst], Basics.BITNOT[lMask]];
StoreWord[dst, Basics.BITOR[curVal, dstValue]];
};
ComputeDstValue:
PROC[longSrcHi, longSrcLo: DragOps.Word, dst: DragonPointer]
RETURNS[srcWord, dstValue: DragOps.Word] = {
srcWord ← LOOPHOLE[Basics.DoubleWordShiftLeft[LOOPHOLE[longSrcHi], LOOPHOLE[longSrcLo], skew]];
IF srcFunc = complement THEN srcWord ← Basics.BITNOT[srcWord];
dstValue
← SELECT dstFunc
FROM
null => srcWord,
and => Basics.BITAND[srcWord, FetchWord[dst]],
or => Basics.BITOR[srcWord, FetchWord[dst]],
xor => Basics.BITXOR[srcWord, FetchWord[dst]],
ENDCASE => ERROR InvalidBitBltCall;
};
FetchWord:
PROC[ptr: DragonPointer]
RETURNS[DragOps.Word] =
TRUSTED {
x: DragonPointer = LOOPHOLE[2*LOOPHOLE[ptr, INT]];
RETURN[x^];
};
StoreWord:
PROC[ptr: DragonPointer, value: DragOps.Word] =
TRUSTED {
x: DragonPointer = LOOPHOLE[2*LOOPHOLE[ptr, INT]];
x^ ← value;
};
GrayInc:
PROC[src: DragonPointer, count:
INT]
RETURNS[DragonPointer] = {
inc: INT;
IF grayWidth.wVal = 1
THEN
RETURN[src]
-- special case
ELSE inc ← count MOD grayWidth.wVal;
RETURN[LOOPHOLE[LOOPHOLE[src, INT]+inc]];
};
RMask:
PROC[bitNum: [0..bitsPerWord)]
RETURNS[DragOps.Word] = {
SELECT bitNum
FROM
0 => RETURN[DragOps.OnesWord]; -- really bit 32
ENDCASE => RETURN[Basics.BITNOT[MaskArray[bitNum]] ];
};
MaskArray[ 0] ← DragOps.OnesWord;
MaskArray[ 1] ← LOOPHOLE[17777777777B];
MaskArray[ 2] ← LOOPHOLE[ 7777777777B];
MaskArray[ 3] ← LOOPHOLE[ 3777777777B];
MaskArray[ 4] ← LOOPHOLE[ 1777777777B];
MaskArray[ 5] ← LOOPHOLE[ 777777777B];
MaskArray[ 6] ← LOOPHOLE[ 377777777B];
MaskArray[ 7] ← LOOPHOLE[ 177777777B];
MaskArray[ 8] ← LOOPHOLE[ 77777777B];
MaskArray[ 9] ← LOOPHOLE[ 37777777B];
MaskArray[10] ← LOOPHOLE[ 17777777B];
MaskArray[11] ← LOOPHOLE[ 7777777B];
MaskArray[12] ← LOOPHOLE[ 3777777B];
MaskArray[13] ← LOOPHOLE[ 1777777B];
MaskArray[14] ← LOOPHOLE[ 777777B];
MaskArray[15] ← LOOPHOLE[ 377777B];
MaskArray[16] ← LOOPHOLE[ 177777B];
MaskArray[17] ← LOOPHOLE[ 77777B];
MaskArray[18] ← LOOPHOLE[ 37777B];
MaskArray[19] ← LOOPHOLE[ 17777B];
MaskArray[20] ← LOOPHOLE[ 7777B];
MaskArray[21] ← LOOPHOLE[ 3777B];
MaskArray[22] ← LOOPHOLE[ 1777B];
MaskArray[23] ← LOOPHOLE[ 777B];
MaskArray[24] ← LOOPHOLE[ 377B];
MaskArray[25] ← LOOPHOLE[ 177B];
MaskArray[26] ← LOOPHOLE[ 77B];
MaskArray[27] ← LOOPHOLE[ 37B];
MaskArray[28] ← LOOPHOLE[ 17B];
MaskArray[29] ← LOOPHOLE[ 7B];
MaskArray[30] ← LOOPHOLE[ 3B];
MaskArray[31] ← LOOPHOLE[ 1B];