DragonBitBltImpl.mesa
Copyright (C) 1986 by Xerox Corporation. All rights reserved.
Willie-Sue, September 12, 1986 2:50:40 pm PDT
DIRECTORY
Basics,
DragOpsCross,
DragOpsCrossUtils,
DragonBitBlt;
DragonBitBltImpl: MONITOR
IMPORTS
Basics, DragOpsCrossUtils
EXPORTS DragonBitBlt
= BEGIN OPEN DragOpsCrossUtils;
BitAddress: TYPE = DragonBitBlt.DragonBitAddress;
DragonPointer: TYPE = DragonBitBlt.DragonPointer;
bitsPerWord: CARDINAL = DragOpsCross.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: DragonBitBlt.SrcFunc ← null;
dstFunc: DragonBitBlt.DstFunc ← null;
srcInc, dstInc: BitBltInc;
goingForward: BOOLTRUE;
MaskArray: ARRAY [0..bitsPerWord] OF DragOpsCross.Word;
isThin: BOOLFALSE;   -- true if dest is all within one word
lMask: DragOpsCross.Word;
rMask: DragOpsCross.Word;
skew: DragOpsCross.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: BOOLFALSE;
grayParam: DragonBitBlt.GrayParm;
grayWidth: BitBltInc;
grayBump: BitBltInc;
lastGray: [0..15);
InvalidBitBltCall: ERROR = CODE;
BITBLT: PUBLIC ENTRY PROC[bbt: DragonBitBlt.BitBltTablePtr] = {
BITBLT: PUBLIC PROC[bbt: DragonBitBlt.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: DragonBitBlt.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;
dstAddr ← bbt.dst;
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, DragOpsCross.logBitsPerWord];
wordPart: INT ← IntShiftRight[absBits, 5]; -- DragOpsCross.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: DragOpsCross.SixBitIndex] RETURNS [INT] = TRUSTED INLINE {
OPEN Basics;
RETURN [LOOPHOLE[ DoubleShiftRight[LOOPHOLE[x, LongNumber], dist], INT] ];
};
IntAnd: PROC[x, y: INT] RETURNS [INT] = TRUSTED INLINE {
OPEN Basics;
RETURN [
LOOPHOLE[ DoubleAnd[LOOPHOLE[x, LongNumber], LOOPHOLE[y, LongNumber]], INT] ];
};
Recompute: PROC[bbt: DragonBitBlt.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: DragOpsCross.Word;
dstValue, srcWord, curVal: DragOpsCross.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: DragOpsCross.Word = DragAnd[lMask, rMask];
curVal ← DragAnd[FetchWord[dst], DragNot[doubleMask]];
dstValue ← DragAnd[dstValue, doubleMask];
dst^ ← DragOr[curVal, dstValue];
StoreWord[dst, DragOr[curVal, dstValue] ];
RETURN;
};
dstValue ← DragAnd[dstValue, lMask];  -- at left side, so do left mask
curVal ← DragAnd[FetchWord[dst], DragNot[lMask]];
dstValue ← DragOr[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 ← DragAnd[FetchWord[dst], DragNot[rMask] ];
dstValue ← DragAnd[dstValue, rMask];  -- at right side, so do right mask
StoreWord[dst, DragOr[curVal, dstValue] ];
};
BltOneLineForwardGray: PROC = TRUSTED {
src: DragonPointer ← srcAddr.word;
dst: DragonPointer ← dstAddr.word;
longSrcHi, longSrcLo: DragOpsCross.Word;
dstValue, srcWord, curVal: DragOpsCross.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: DragOpsCross.Word = DragAnd[lMask, rMask];
curVal ← DragAnd[FetchWord[dst], DragNot[doubleMask]];
dstValue ← DragAnd[dstValue, doubleMask];
StoreWord[dst, DragOr[curVal, dstValue]];
RETURN;
};
dstValue ← DragAnd[dstValue, lMask];  -- at left side, do left mask
curVal ← DragAnd[FetchWord[dst], DragNot[lMask]];
dstValue ← DragOr[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 ← DragAnd[FetchWord[dst], DragNot[rMask] ];
dstValue ← DragAnd[dstValue, rMask];  -- at right side, so do right mask
StoreWord[dst, DragOr[curVal, dstValue]];
};
BltOneLineBackward: PROC = TRUSTED {
src: DragonPointer ← LOOPHOLE[srcAddr.word + sWidth - 1];
dst: DragonPointer ← LOOPHOLE[dstAddr.word + dWidth - 1];
longSrcHi, longSrcLo: DragOpsCross.Word;
dstValue, srcWord, curVal: DragOpsCross.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: DragOpsCross.Word = DragAnd[lMask, rMask];
curVal ← DragAnd[FetchWord[dst], DragNot[doubleMask]];
dstValue ← DragAnd[dstValue, doubleMask];
StoreWord[dst, DragOr[curVal, dstValue]];
RETURN;
};
dstValue ← DragAnd[dstValue, rMask];  -- at right side, do right mask
curVal ← DragAnd[FetchWord[dst], DragNot[rMask] ];
dstValue ← DragOr[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 ← DragAnd[dstValue, lMask];  -- at left side, so do left mask
curVal ← DragAnd[FetchWord[dst], DragNot[lMask]];
StoreWord[dst, DragOr[curVal, dstValue]];
};
ComputeDstValue: PROC[longSrcHi, longSrcLo: DragOpsCross.Word, dst: DragonPointer]
RETURNS[srcWord, dstValue: DragOpsCross.Word] = {
srcWord ← DragOpsCrossUtils.DoubleWordShiftLeft[longSrcHi, longSrcLo, skew];
IF srcFunc = complement THEN srcWord ← DragNot[srcWord];
dstValue ← SELECT dstFunc FROM
null => srcWord,
and => DragAnd[srcWord, FetchWord[dst]],
or => DragOr[srcWord, FetchWord[dst]],
xor => DragXor[srcWord, FetchWord[dst]],
ENDCASE => ERROR InvalidBitBltCall;
};
FetchWord: PROC[ptr: DragonPointer] RETURNS[DragOpsCross.Word] = TRUSTED {
x: DragonPointer = LOOPHOLE[2*LOOPHOLE[ptr, INT]];
RETURN[x^];
};
StoreWord: PROC[ptr: DragonPointer, value: DragOpsCross.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[DragOpsCross.Word] = {
SELECT bitNum FROM
0 => RETURN[DragOpsCross.OnesWord];  -- really bit 32
ENDCASE => RETURN[DragNot[MaskArray[bitNum]] ];
};
MaskArray[ 0] ← DragOpsCross.OnesWord;
MaskArray[ 1] ← DragOpsCrossUtils.IntToWord[17777777777B];
MaskArray[ 2] ← DragOpsCrossUtils.IntToWord[ 7777777777B];
MaskArray[ 3] ← DragOpsCrossUtils.IntToWord[ 3777777777B];
MaskArray[ 4] ← DragOpsCrossUtils.IntToWord[ 1777777777B];
MaskArray[ 5] ← DragOpsCrossUtils.IntToWord[ 777777777B];
MaskArray[ 6] ← DragOpsCrossUtils.IntToWord[ 377777777B];
MaskArray[ 7] ← DragOpsCrossUtils.IntToWord[ 177777777B];
MaskArray[ 8] ← DragOpsCrossUtils.IntToWord[ 77777777B];
MaskArray[ 9] ← DragOpsCrossUtils.IntToWord[ 37777777B];
MaskArray[10] ← DragOpsCrossUtils.IntToWord[ 17777777B];
MaskArray[11] ← DragOpsCrossUtils.IntToWord[ 7777777B];
MaskArray[12] ← DragOpsCrossUtils.IntToWord[ 3777777B];
MaskArray[13] ← DragOpsCrossUtils.IntToWord[ 1777777B];
MaskArray[14] ← DragOpsCrossUtils.IntToWord[ 777777B];
MaskArray[15] ← DragOpsCrossUtils.IntToWord[ 377777B];
MaskArray[16] ← DragOpsCrossUtils.IntToWord[LONG[177777B]];
MaskArray[17] ← DragOpsCrossUtils.IntToWord[LONG[ 77777B]];
MaskArray[18] ← DragOpsCrossUtils.IntToWord[LONG[ 37777B]];
MaskArray[19] ← DragOpsCrossUtils.IntToWord[LONG[ 17777B]];
MaskArray[20] ← DragOpsCrossUtils.IntToWord[LONG[ 7777B]];
MaskArray[21] ← DragOpsCrossUtils.IntToWord[LONG[ 3777B]];
MaskArray[22] ← DragOpsCrossUtils.IntToWord[LONG[ 1777B]];
MaskArray[23] ← DragOpsCrossUtils.IntToWord[LONG[ 777B]];
MaskArray[24] ← DragOpsCrossUtils.IntToWord[LONG[ 377B]];
MaskArray[25] ← DragOpsCrossUtils.IntToWord[LONG[ 177B]];
MaskArray[26] ← DragOpsCrossUtils.IntToWord[LONG[ 77B]];
MaskArray[27] ← DragOpsCrossUtils.IntToWord[LONG[ 37B]];
MaskArray[28] ← DragOpsCrossUtils.IntToWord[LONG[ 17B]];
MaskArray[29] ← DragOpsCrossUtils.IntToWord[LONG[ 7B]];
MaskArray[30] ← DragOpsCrossUtils.IntToWord[LONG[ 3B]];
MaskArray[31] ← DragOpsCrossUtils.IntToWord[LONG[ 1B]];
END.