<> <> <> <> DIRECTORY Basics, DragOps, DragOpsUtils, BitBlt; BitBltImpl: MONITOR IMPORTS Basics 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 <> < 2 => left partial, dWidth-2 full words, and right partial>> < left partial, right partial only>> < entire destination within one word - special case as both masks need to be applied at the same time>> extraWordAtLeft, extraWordAtRight: BOOL; <> <> <> < 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 PROC[bbt: BitBlt.BitBltTablePtr] = { < 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] = { <> <> <> <<(~bbt.flags.gray AND LOOPHOLE[bbt.srcDesc, INTEGER] = 0) OR -- bbt.dstBpl = 0 OR>> < 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]; <> 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; <<>> <> 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, 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] = { <> 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]; <> 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]; END.