<> <> <> <<>> DIRECTORY Basics, CountedVM, FunctionCache, PrincOps, PrincOpsUtils, VM, SampleMapOps; SampleMapOpsImpl: CEDAR MONITOR IMPORTS Basics, CountedVM, FunctionCache, PrincOpsUtils, VM EXPORTS SampleMapOps ~ BEGIN bitsPerWord: NAT ~ Basics.bitsPerWord; Buffer: TYPE ~ SampleMapOps.Buffer; BufferRep: TYPE ~ SampleMapOps.BufferRep; maxCount: NAT ~ SampleMapOps.maxCount; CVEC: TYPE ~ SampleMapOps.CVEC; Function: TYPE ~ SampleMapOps.Function; nullFunction: Function ~ SampleMapOps.nullFunction; lastCVEC: CVEC ~ SampleMapOps.lastCVEC; logBitsPerWord: NAT ~ Basics.logBitsPerWord; SampleMap: TYPE ~ SampleMapOps.SampleMap; SampleMapRep: TYPE ~ SampleMapOps.SampleMapRep; SubMap: TYPE ~ SampleMapOps.SubMap; MultipleReleaseOfScratch: PUBLIC ERROR ~ CODE; BITAND: PROC [a, b: CARDINAL] RETURNS [CARDINAL] ~ INLINE {RETURN[Basics.BITAND[a, b]]}; Shift: PROC [a: CARDINAL, b: INTEGER] RETURNS [CARDINAL] ~ INLINE {RETURN[Basics.BITSHIFT[a, b]]}; Check: PROC[x: CARDINAL, max: NAT] RETURNS [NAT] ~ TRUSTED MACHINE CODE { PrincOps.zINC; PrincOps.zBNDCK }; <> IsPowerOfTwo: PROC [c: CARDINAL] RETURNS [BOOLEAN] ~ INLINE { RETURN [BITAND[c, c-1] = 0] }; WordCountFromBit: PROC [bitCount: LONG CARDINAL] RETURNS [LONG CARDINAL] ~ { RETURN [Basics.DoubleShiftRight[[lc[bitCount+(bitsPerWord-1)]], logBitsPerWord].lc] }; Lg: PROC [a: NAT] RETURNS [lg: NAT _ 0] ~ { b: CARDINAL _ 1; UNTIL b >= a DO lg _ lg + 1; b _ b*2; ENDLOOP; }; RoundUp: PROC [a: NAT] RETURNS [NAT] ~ INLINE { <> RETURN [BITAND[a+(bitsPerWord-1), CARDINAL.LAST-(bitsPerWord-1)]] }; ComputeWords: PUBLIC PROC [sSize: CARDINAL, fSize: CARDINAL, bitsPerSample: [0..bitsPerWord]] RETURNS [LONG CARDINAL] ~ { bitsPerLine: NAT ~ RoundUp[Basics.LongMult[fSize, bitsPerSample]]; RETURN [Basics.LongMult[sSize, bitsPerLine/bitsPerWord]] }; nullBitBltTable: PrincOps.BitBltTable ~ [ dst: [word: NIL, bit: 0], dstBpl: 0, src: [word: NIL, bit: 0], srcDesc: [srcBpl[0]], width: 0, height: 0, flags: [] ]; disjointBitBltTable: PrincOps.BitBltTable ~ [ dst: [word: NIL, bit: 0], dstBpl: 0, src: [word: NIL, bit: 0], srcDesc: [srcBpl[0]], width: 0, height: 0, flags: [disjoint: TRUE, disjointItems: TRUE] ]; grayBitBltTable: PrincOps.BitBltTable ~ [ dst: [word: NIL, bit: 0], dstBpl: 0, src: [word: NIL, bit: 0], srcDesc: [srcBpl[0]], width: 0, height: 0, flags: [disjoint: TRUE, disjointItems: TRUE, gray: TRUE] ]; UnsafeCreate: PUBLIC UNSAFE PROC [sSize: CARDINAL, fSize: CARDINAL, bitsPerSample: [0..Basics.bitsPerWord], bitsPerLine: NAT, base: PrincOps.BitAddress, nWords: LONG CARDINAL, ref: REF, scratchDescriptor: SampleMap _ NIL] RETURNS [SampleMap] ~ { dataBitsPerLine: LONG CARDINAL ~ Basics.LongMult[fSize, bitsPerSample]; fillBits: NAT ~ bitsPerLine-dataBitsPerLine; totalBits: LONG CARDINAL ~ Basics.LongMult[sSize, bitsPerLine]-fillBits+base.bit; wrds: LONG CARDINAL ~ WordCountFromBit[totalBits]; check: BOOL[FALSE..FALSE] ~ (nWords < wrds); s: SampleMap ~ IF scratchDescriptor#NIL THEN scratchDescriptor ELSE NEW[SampleMapRep]; s^ _ [ sSize: sSize, fSize: fSize, bitsPerSample: bitsPerSample, base: base, bitsPerLine: bitsPerLine, ref: ref ]; RETURN [s]; }; smallSize: NAT _ 511; WordSeqRep: TYPE ~ RECORD [SEQUENCE length: NAT OF WORD]; Create: PUBLIC PROC [sSize: CARDINAL, fSize: CARDINAL, bitsPerSample: [0..Basics.bitsPerWord]] RETURNS [SampleMap] ~ { bitsPerLine: NAT ~ RoundUp[Basics.LongMult[fSize, bitsPerSample]]; nWords: LONG CARDINAL ~ Basics.LongMult[sSize, bitsPerLine/bitsPerWord]; IF nWords <= smallSize THEN TRUSTED { words: NAT _ MAX[NAT[nWords], 1]; wordSeq: REF WordSeqRep _ NEW[WordSeqRep[words]]; RETURN [UnsafeCreate[ sSize: sSize, fSize: fSize, bitsPerSample: bitsPerSample, bitsPerLine: bitsPerLine, base: [word: @wordSeq[0], bit: 0], nWords: words, ref: wordSeq ]] } ELSE { vm: CountedVM.Handle ~ Allocate[nWords]; RETURN [FromVM[ sSize: sSize, fSize: fSize, bitsPerSample: bitsPerSample, vm: vm ]]; }; }; Allocate: PROC [nWords: LONG CARDINAL] RETURNS [vm: CountedVM.Handle _ NIL] ~ { nWords _ MAX[nWords, 256]; vm _ CountedVM.SimpleAllocate[nWords ! VM.CantAllocate => CONTINUE]; IF vm = NIL THEN { <> cache: FunctionCache.Cache ~ FunctionCache.GlobalCache[]; info: FunctionCache.CacheInfo ~ FunctionCache.GetInfo[cache]; FunctionCache.SetLimits[cache, 0, 0]; FunctionCache.SetLimits[x: cache, maxEntries: info.maxEntries, maxTotalSize: info.maxTotalSize]; ClearScratch[]; vm _ CountedVM.SimpleAllocate[nWords]; }; }; FromVM: PUBLIC PROC [sSize: CARDINAL, fSize: CARDINAL, bitsPerSample: [0..Basics.bitsPerWord], vm: CountedVM.Handle] RETURNS [SampleMap] ~ TRUSTED { RETURN [UnsafeCreate[ sSize: sSize, fSize: fSize, bitsPerSample: bitsPerSample, bitsPerLine: RoundUp[fSize*bitsPerSample], base: [word: vm.pointer, bit: 0], nWords: vm.words, ref: vm ]] }; FromSubMap: PUBLIC PROC [subMap: SubMap] RETURNS [SampleMap] ~ TRUSTED { s: SampleMap ~ NEW[SampleMapRep _ subMap.sampleMap^]; bitsPerLine: NAT ~ s.bitsPerLine; bitsPerSample: NAT ~ s.bitsPerSample; sMin: NAT ~ Check[subMap.start.s, s.sSize]; fMin: NAT ~ Check[subMap.start.f, s.fSize]; sSize: NAT ~ MIN[subMap.size.s, LOOPHOLE[s.sSize-sMin, NAT]]; fSize: NAT ~ MIN[subMap.size.f, LOOPHOLE[s.fSize-fMin, NAT]]; skipBits: LONG CARDINAL ~ Basics.LongMult[sMin, bitsPerLine] + Basics.LongMult[fMin, bitsPerSample] + s.base.bit; s.sSize _ sSize; s.fSize _ fSize; s.base _ IndexBit[s.base.word, [lc[skipBits]]]; RETURN [s]; }; Copy: PUBLIC PROC [subMap: SubMap] RETURNS [SampleMap] ~ { s: SampleMap ~ subMap.sampleMap; sMin: NAT ~ Check[subMap.start.s, s.sSize]; fMin: NAT ~ Check[subMap.start.f, s.fSize]; sSize: NAT ~ MIN[subMap.size.s, LOOPHOLE[s.sSize-sMin, NAT]]; fSize: NAT ~ MIN[subMap.size.f, LOOPHOLE[s.fSize-fMin, NAT]]; new: SampleMap ~ Create[sSize: sSize, fSize: fSize, bitsPerSample: s.bitsPerSample]; Transfer[dest: new, destStart: [0, 0], source: subMap, function: [null, null]]; RETURN [new]; }; nScratch: NAT ~ 5; scratchRefs: ARRAY [0..nScratch) OF SampleMap _ ALL[NIL]; ObtainScratch: PUBLIC PROC [sSize: CARDINAL, fSize: CARDINAL, bitsPerSample: [0..Basics.bitsPerWord]] RETURNS [SampleMap] ~ { TryObtainScratch: ENTRY PROC RETURNS [SampleMap] ~ TRUSTED INLINE { bitsPerLine: NAT ~ RoundUp[Basics.LongMult[fSize, bitsPerSample]]; nWords: INT ~ LOOPHOLE[Basics.LongMult[sSize, bitsPerLine/bitsPerWord]]; FOR i: NAT IN [0..nScratch) DO s: SampleMap _ scratchRefs[i]; IF s # NIL THEN WITH s.ref SELECT FROM vm: CountedVM.Handle => { IF vm.words >= nWords THEN { scratchRefs[i] _ NIL; s.sSize _ sSize; s.fSize _ fSize; s.bitsPerSample _ bitsPerSample; s.bitsPerLine _ bitsPerLine; RETURN [s] }; }; ENDCASE => NULL; ENDLOOP; RETURN [NIL] }; s: SampleMap _ TryObtainScratch[]; IF s = NIL THEN { nWords: INT ~ ComputeWords[sSize, fSize, bitsPerSample]; vm: CountedVM.Handle ~ Allocate[nWords]; s _ FromVM[sSize: sSize, fSize: fSize, bitsPerSample: bitsPerSample, vm: vm]; }; RETURN [s] }; ReleaseScratch: PUBLIC ENTRY PROC [sampleMap: SampleMap] ~ { r: SampleMap _ sampleMap; FOR i: NAT IN [0..nScratch) UNTIL r = NIL DO <> t: SampleMap _ scratchRefs[i]; scratchRefs[i] _ r; r _ t; IF r = sampleMap THEN RETURN WITH ERROR MultipleReleaseOfScratch; ENDLOOP; }; ClearScratch: ENTRY PROC ~ { FOR i: NAT IN [0..nScratch) DO scratchRefs[i] _ NIL; ENDLOOP; }; DoWithScratch: PUBLIC PROC [sSize: CARDINAL, fSize: CARDINAL, bitsPerSample: [0..Basics.bitsPerWord], action: PROC[SampleMap]] ~ { scratch: SampleMap ~ ObtainScratch[sSize, fSize, bitsPerSample]; action[scratch ! UNWIND => ReleaseScratch[scratch]]; ReleaseScratch[scratch]; }; Size: PUBLIC PROC [sampleMap: SampleMap] RETURNS [CVEC] ~ {RETURN [[s: sampleMap.sSize, f: sampleMap.fSize]]}; Clear: PUBLIC PROC [sampleMap: SampleMap] ~ TRUSTED { bitsPerLine: NAT ~ sampleMap.bitsPerLine; pointer: LONG POINTER _ sampleMap.base.word; fillBitsPerLine: NAT ~ bitsPerLine - sampleMap.bitsPerSample*sampleMap.fSize; IF fillBitsPerLine < bitsPerWord THEN { <> nBits: LONG CARDINAL ~ Basics.LongMult[bitsPerLine, sampleMap.sSize]+sampleMap.base.bit-fillBitsPerLine; nWords: LONG CARDINAL _ WordCountFromBit[nBits]; WHILE nWords > 32768 DO PrincOpsUtils.LongZero[pointer, 32768]; pointer _ pointer + 32768; nWords _ nWords - 32768; ENDLOOP; PrincOpsUtils.LongZero[pointer, nWords]; } ELSE { <> dataBitsPlus: NAT ~ sampleMap.bitsPerSample*sampleMap.fSize + (bitsPerWord-1); bit: CARDINAL _ sampleMap.base.bit; FOR i: NAT IN [0..sampleMap.sSize) DO PrincOpsUtils.LongZero[where: pointer, nwords: (bit + dataBitsPlus)/bitsPerWord]; bit _ bit + bitsPerLine; pointer _ pointer + bit/bitsPerWord; bit _ bit MOD bitsPerWord; ENDLOOP; }; }; <<>> GetSample: PUBLIC PROC [sampleMap: SampleMap, index: CVEC] RETURNS [CARDINAL] ~ TRUSTED { s: CARDINAL ~ Basics.BoundsCheck[index.s, sampleMap.sSize]; f: CARDINAL ~ Basics.BoundsCheck[index.f, sampleMap.fSize]; bitsPerSample: NAT ~ sampleMap.bitsPerSample; bitIndex: LONG CARDINAL ~ sampleMap.base.bit + Basics.LongMult[s, sampleMap.bitsPerLine] + Basics.LongMult[f, bitsPerSample]; bitAddress: PrincOps.BitAddress ~ IndexBit[sampleMap.base.word, [lc[bitIndex]]]; pointer: LONG POINTER TO ARRAY [0..1] OF WORD ~ bitAddress.word; shiftAmt: INTEGER ~ bitAddress.bit + bitsPerSample - bitsPerWord; mask: CARDINAL ~ Shift[1, bitsPerSample]-1; shiftedBits: CARDINAL ~ IF shiftAmt <= 0 THEN Shift[pointer^[0], shiftAmt] ELSE Shift[pointer^[0], shiftAmt] + Shift[pointer^[1], shiftAmt-16]; RETURN [BITAND[shiftedBits, mask]] }; PutSample: PUBLIC PROC [sampleMap: SampleMap, index: CVEC, value: CARDINAL, function: Function] ~ TRUSTED { s: CARDINAL ~ Basics.BoundsCheck[index.s, sampleMap.sSize]; f: CARDINAL ~ Basics.BoundsCheck[index.f, sampleMap.fSize]; bitsPerSample: NAT ~ sampleMap.bitsPerSample; bitIndex: LONG CARDINAL ~ sampleMap.base.bit + Basics.LongMult[s, sampleMap.bitsPerLine] + Basics.LongMult[f, bitsPerSample]; bbTableSpace: PrincOps.BBTableSpace; bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace]; bb^ _ [ dst: IndexBit[sampleMap.base.word, [lc[bitIndex]]], dstBpl: 0, src: [word: @value, bit: bitsPerWord-bitsPerSample], srcDesc: [srcBpl[0]], height: 1, width: bitsPerSample, flags: [direction: forward, disjoint: TRUE, disjointItems: TRUE, gray: FALSE, srcFunc: function.srcFunc, dstFunc: function.dstFunc] ]; PrincOpsUtils.BITBLT[bb]; }; DumbTransfer: PROC [dest: SampleMap, destStart: CVEC, source: SubMap, function: Function] ~ { sSize: NAT ~ MIN[source.size.s, dest.sSize-destStart.s, source.sampleMap.sSize-source.start.s]; fSize: NAT ~ MIN[source.size.f, dest.fSize-destStart.f, source.sampleMap.fSize-source.start.f]; FOR s: NAT IN [0..sSize) DO FOR f: NAT IN [0..fSize) DO sample: CARDINAL ~ GetSample[source.sampleMap, [source.start.s+s, source.start.f+f]]; PutSample[dest, [destStart.s+s, destStart.f+f], sample, function]; ENDLOOP; ENDLOOP; }; BitAddressOverlay: TYPE ~ MACHINE DEPENDENT RECORD [ <> SELECT OVERLAID * FROM ba => [bitAddress: PrincOps.BitAddress], ov => [pointer: LONG POINTER, offset: CARDINAL], ENDCASE ]; IndexBit: UNSAFE PROC [pointer: LONG POINTER, bitOffset: Basics.LongNumber] RETURNS [PrincOps.BitAddress] ~ UNCHECKED INLINE { addr: BitAddressOverlay ~ [ov[ pointer: pointer + Basics.DoubleShiftRight[bitOffset, logBitsPerWord].lc, offset: bitOffset.lo MOD bitsPerWord ]]; RETURN [addr.bitAddress] }; Transfer: PUBLIC PROC [dest: SampleMap, destStart: CVEC, source: SubMap, function: Function] ~ TRUSTED { bps: NAT ~ dest.bitsPerSample; src: SampleMap ~ source.sampleMap; sSize: NAT ~ MIN[source.size.s, dest.sSize-destStart.s, source.sampleMap.sSize-source.start.s]; fSize: NAT ~ MIN[source.size.f, src.fSize-source.start.f, dest.fSize-destStart.f]; SELECT TRUE FROM source.sampleMap.bitsPerSample = bps => { bbTableSpace: PrincOps.BBTableSpace; bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace]; dstBitIndex: LONG CARDINAL ~ dest.base.bit + Basics.LongMult[Check[destStart.s, dest.sSize], dest.bitsPerLine] + Basics.LongMult[Check[destStart.f, dest.fSize], bps]; srcBitIndex: LONG CARDINAL ~ src.base.bit + Basics.LongMult[Check[source.start.s, src.sSize], src.bitsPerLine] + Basics.LongMult[Check[source.start.f, src.fSize], bps]; bb^ _ disjointBitBltTable; bb.dst _ IndexBit[dest.base.word, [lc[dstBitIndex]]]; bb.dstBpl _ dest.bitsPerLine; bb.src _ IndexBit[src.base.word, [lc[srcBitIndex]]]; bb.srcDesc _ [srcBpl[src.bitsPerLine]]; bb.height _ sSize; bb.width _ fSize * bps; bb.flags.srcFunc _ function.srcFunc; bb.flags.dstFunc _ function.dstFunc; PrincOpsUtils.BITBLT[bb]; }; ENDCASE => DumbTransfer[dest, destStart, source, function]; }; Move: PUBLIC PROC [sampleMap: SampleMap, destStart: CVEC, sourceStart: CVEC, size: CVEC, function: Function] ~ TRUSTED { bps: NAT ~ sampleMap.bitsPerSample; bpl: NAT ~ sampleMap.bitsPerLine; sSize: NAT ~ sampleMap.sSize; fSize: NAT ~ sampleMap.fSize; bbTableSpace: PrincOps.BBTableSpace; bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace]; dstBitIndex: LONG CARDINAL _ sampleMap.base.bit + Basics.LongMult[Check[destStart.s, sSize], bpl] + Basics.LongMult[Check[destStart.f, fSize], bps]; srcBitIndex: LONG CARDINAL _ sampleMap.base.bit + Basics.LongMult[Check[sourceStart.s, sSize], bpl] + Basics.LongMult[Check[sourceStart.f, fSize], bps]; sSamples: NAT ~ MIN[size.s, sSize-sourceStart.s, sSize-destStart.s]; fSamples: NAT ~ MIN[size.f, fSize-sourceStart.f, fSize-destStart.f]; bb^ _ disjointBitBltTable; bb.dstBpl _ bpl; bb.srcDesc _ [srcBpl[bpl]]; bb.height _ sSamples; bb.width _ bps * fSamples; bb.flags.srcFunc _ function.srcFunc; bb.flags.dstFunc _ function.dstFunc; IF sSamples > 0 AND (sourceStart.f+fSamples) > destStart.f AND (destStart.f+fSamples) > sourceStart.f AND (sourceStart.s+sSamples) > destStart.s AND (destStart.s+sSamples) > sourceStart.s THEN { bb.flags.disjoint _ FALSE; -- the rectangles overlap IF sourceStart.s=destStart.s THEN bb.flags.disjointItems _ FALSE; -- so do the items IF destStart.s>sourceStart.s OR (destStart.s=sourceStart.s AND destStart.f>sourceStart.f) THEN { -- reverse direction delta: LONG CARDINAL _ Basics.LongMult[sSamples-1, bpl]; bb.flags.direction _ backward; bb.srcDesc.srcBpl _ bb.dstBpl _ -bb.dstBpl; dstBitIndex _ dstBitIndex + delta; srcBitIndex _ srcBitIndex + delta; }; }; bb.dst _ IndexBit[sampleMap.base.word, [lc[dstBitIndex]]]; bb.src _ IndexBit[sampleMap.base.word, [lc[srcBitIndex]]]; PrincOpsUtils.BITBLT[bb]; }; DumbFill: PROC [dest: SubMap, value: CARDINAL, function: Function] ~ { sSize: NAT ~ MIN[dest.size.s, dest.sampleMap.sSize-dest.start.s]; fSize: NAT ~ MIN[dest.size.f, dest.sampleMap.fSize-dest.start.f]; FOR s: NAT IN [0..sSize) DO FOR f: NAT IN [0..fSize) DO PutSample[dest.sampleMap, [dest.start.s+s, dest.start.f+f], value, function]; ENDLOOP; ENDLOOP; }; replicator: ARRAY [0..4] OF CARDINAL ~ [0FFFFH, 05555H, 01111H, 00101H, 00001H]; Fill: PUBLIC PROC [dest: SubMap, value: CARDINAL, function: Function] ~ { bps: NAT ~ dest.sampleMap.bitsPerSample; IF bitsPerWord MOD bps = 0 THEN TRUSTED { dstBitIndex: LONG CARDINAL ~ dest.sampleMap.base.bit + Basics.LongMult[Check[dest.start.s, dest.sampleMap.sSize], dest.sampleMap.bitsPerLine] + Basics.LongMult[Check[dest.start.f, dest.sampleMap.fSize], bps]; sSize: NAT ~ MIN[dest.size.s, dest.sampleMap.sSize-dest.start.s]; fSize: NAT ~ MIN[dest.size.f, dest.sampleMap.fSize-dest.start.f]; bbTableSpace: PrincOps.BBTableSpace; bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace]; replicatedPixel: CARDINAL _ BITAND[value, Shift[1, bps]-1] * replicator[Lg[bps]]; IF function = [null, complement] THEN { <> replicatedPixel _ CARDINAL.LAST-replicatedPixel; function _ [null, null]; }; bb^ _ grayBitBltTable; bb.dst _ IndexBit[dest.sampleMap.base.word, [lc[dstBitIndex]]]; bb.dstBpl _ dest.sampleMap.bitsPerLine; bb.src.word _ @replicatedPixel; bb.height _ MIN[dest.size.s, dest.sampleMap.sSize-dest.start.s]; bb.width _ bps*MIN[dest.size.f, dest.sampleMap.fSize-dest.start.f]; bb.flags.srcFunc _ function.srcFunc; bb.flags.dstFunc _ function.dstFunc; PrincOpsUtils.BITBLT[bb]; } ELSE DumbFill[dest, value, function]; }; TileBox: PUBLIC PROC [dest: SampleMap, start: CVEC, size: CVEC, source: SampleMap, s0, f0: INTEGER, phase: NAT, function: Function] ~ { boxes: PROC[box: BoxProc] ~ {box[start.s, start.f, start.s+size.s, start.f+size.f]}; TileBoxes[dest, boxes, source, s0, f0, phase, function]; }; QR: TYPE ~ RECORD [quotient: INTEGER, remainder: NAT]; DivMod: PROC [n: INTEGER, d: NAT] RETURNS [qr: QR] ~ { <> IF d#1 THEN { nn: Basics.LongNumber _ [li[n]]; qq: Basics.LongNumber _ [lc[0]]; IF nn.li < 0 THEN {nn.highbits _ nn.highbits + d; -- qq.highbits _ CARDINAL.LAST --}; [quotient: qq.lowbits, remainder: qr.remainder] _ Basics.LongDivMod[nn.lc, d]; <> qr.quotient _ LOOPHOLE[qq.lowbits]; } ELSE RETURN [[quotient: n, remainder: 0]]; }; Mod: PROC [n: INT, d: NAT] RETURNS [remainder: NAT] ~ { <> IF d#1 THEN { nn: Basics.LongNumber _ [li[n]]; WHILE nn.li < 0 DO nn.highbits _ nn.highbits + d ENDLOOP; WHILE nn.highbits >= d DO nn.highbits _ nn.highbits - d ENDLOOP; RETURN [Basics.LongDivMod[nn.lc, d].remainder]; } ELSE RETURN [remainder: 0]; }; TileFromStipple: PUBLIC PROC [stipple: CARDINAL, bitsPerSample: [0..bitsPerWord], sample0, sample1: CARDINAL, obtainScratch: BOOL] RETURNS [SampleMap] ~ { easy: BOOL ~ (16 MOD (bitsPerSample*4) = 0) OR (bitsPerSample=8 AND BITAND[stipple, 3333H] = BITAND[stipple/4, 3333H]); fSize: NAT ~ IF easy THEN 16/bitsPerSample ELSE 16; sSize: NAT ~ IF easy THEN 4 ELSE 8; temp: SampleMap ~ ObtainScratch[4, 4, bitsPerSample]; tile: SampleMap ~ (IF obtainScratch THEN ObtainScratch ELSE Create)[sSize: sSize, fSize: fSize, bitsPerSample: bitsPerSample]; Clear[tile]; FOR s: NAT DECREASING IN [0..4) DO FOR f: NAT DECREASING IN [0..4) DO PutSample[temp, [s, f], IF stipple MOD 2 = 0 THEN sample0 ELSE sample1, [null, null]]; stipple _ stipple/2; ENDLOOP; ENDLOOP; TileBox[tile, [0, 0], [sSize, fSize], temp, 0, 0, 0, [null, null]]; ReleaseScratch[temp]; RETURN [tile]; }; Zeros: PROC [pointer: LONG POINTER, count: NAT] RETURNS [BOOL] ~ TRUSTED { <> bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace]; chomp: NAT ~ 8; scratch: ARRAY [0..chomp) OF WORD _ ALL[0]; bbTableSpace: PrincOps.BBTableSpace; bb^ _ disjointBitBltTable; bb.dstBpl _ 0; bb.srcDesc _ [srcBpl[chomp*bitsPerWord]]; bb.height _ count/chomp; bb.width _ chomp*bitsPerWord; bb.flags.srcFunc _ null; bb.flags.dstFunc _ or; bb.dst.word _ @scratch; bb.src.word _ pointer; IF bb.height # 0 THEN PrincOpsUtils.BITBLT[bb]; bb.src.word _ pointer + Basics.LongMult[bb.height, chomp]; bb.height _ 1; bb.width _ count MOD chomp; IF bb.width # 0 THEN PrincOpsUtils.BITBLT[bb]; FOR i: NAT IN [0..MIN[chomp, count]) DO IF scratch[i]#0 THEN RETURN [FALSE] ENDLOOP; RETURN [TRUE]; }; Equal: PUBLIC PROC [a, b: SubMap] RETURNS [BOOL] ~ { sSize: NAT ~ MIN[NAT[a.sampleMap.sSize-a.start.s], a.size.s]; fSize: NAT ~ MIN[NAT[a.sampleMap.fSize-a.start.f], a.size.f]; IF sSize = MIN[NAT[b.sampleMap.sSize-b.start.s], b.size.s] AND fSize = MIN[NAT[b.sampleMap.fSize-b.start.f], b.size.f] AND a.sampleMap.bitsPerSample = b.sampleMap.bitsPerSample THEN { bandSize: NAT _ MIN[MAX[4096/fSize, 1], sSize]; band: SampleMap ~ ObtainScratch[sSize: bandSize, fSize: fSize, bitsPerSample: a.sampleMap.bitsPerSample]; equal: BOOL _ TRUE; Clear[band]; FOR s: NAT _ 0, s+bandSize UNTIL s = sSize DO Transfer[band, [0, 0], [a.sampleMap, [s+a.start.s, a.start.f], [bandSize, fSize]], [null, null]]; Transfer[band, [0, 0], [b.sampleMap, [s+b.start.s, b.start.f], [bandSize, fSize]], [xor, null]]; IF NOT Zeros[band.base.word, ComputeWords[bandSizu, fSize, band.bitsPerSample]] THEN {equal _ FALSE; EXIT}; bandSize _ MIN[sSize-s, bandSize]; ENDLOOP; ReleaseScratch[band]; RETURN [equal]; } ELSE RETURN [FALSE_; }; <<>> IsAll: PUBLIC PROC [subMap: SubMap, value: CARDINAL _ 0] RETURNS [BOOLEAN] ~ { sSize: NAT ~ MIN[NAT[subMap.sampleMap.sSize-subMap.start.s], subMap.size.s]; fSize: NAT ~ MIN[NAT[subMap.sampleMap.fSize-subMap.start.f], subMap.size.f]; bandSize: NAT _ MIN[MAX[4096/fSize, 1], sSize]; band: SampleMap ~ ObtainScratch[sSize: bandSize, fSize: fSize, bitsPerSample: subMap.sampleMap.bitsPerSample]; equal: BOOL _ TRUE; Clear[band]; FOR s: NAT _ 0, s+bandSize UNTIL s = sSize DO Transfer[band, [0, 0], Zs5bMap.sampleMap, [s+subMap.start.s, subMap.start.f], [bandSize, fSize]], [null, null]]; IF value#0 THEN Fill[dest: [band, [0,0], [bandSize, fSize]], value: value, function: [xor, null]]; IF NOT Zeros[band.base.word, ComputeWords[bandSize, fSize, band.bitsPerSample]] THEN {equal _ FALSE; EXIT}; bandSize _ MIN[sSize-s, bandSize]; ENDLOOP; ReleaseScratch[band]; RETURN [equal]; }; Trim: PUBLIC PROC [subMap: SubMap, background: CARDINAL _ 0] RETURNS [SubMap] ~ { sSize: NAT _ MIN[NAT[subMap.sampleMap.sSize-subMap.start.s], subMap.size.s]; fSize: NAT _ MIN[NAT[subMap.sampleMap.fSize-subMap.start.f], subMap.size.f]; band: SampleMap _ ObtainScratch[sSize: 1, fSize: fSize, bitsPerSample: subMap.sampleMap.bitsPerSample]; smin: NAT _ subMap.start.s; smax: NAT _ smin+sSize; fmin: NAT _ subMap.start.f; fmax: NAT _ fmin+fSize; bandWords: NAT ~ ComputeWords[1, fSize, band.bitsPerSample]; Clear[band]; WHILE smin < smax -- OR EXIT below -- DO Transfer[band, [0, 0], [subMap.sampleMap, [smax-1, subMap.start.f], [1, fSize]], [null, null]]; IF background#0 THEN Fill[dest: [band, [0,0], [1, fSize]], value: background, function: [xor, null]]; IF NOT Zeros[band.base.word, bandWords] THEN EXIT; smax _ smax-1; ENDLOOP; WHILE smin < smax -- OR EXIT below -- DO Transfer[band, [0, 0], [subMap.sampleMap, [smin, subMap.start.f], [1, fSize]], [null, null]]; IF background#0 THEN Fill[dest: [band, [0,0], [1, fSize]], value: background, function: [xor, null]]; IF NOT Zeros[band.base.word, bandWords] THEN EXIT; smin _ smin+1; ENDLOOP; ReleaseScratch[band]; band _ NIL; IF smin=smax THEN RETURN [[subMap.sampleMap, [smin, fmin], [0, 0]]]; FOR delta: NAT _ 16, delta/4 UNTIL delta=0 DO WHILE fmin+delta <= fmax AND IsAll[[subMap.sampleMap, [smin, fmax-delta], [smax-smin, delta]], background] DO fmax _ fmax-delta; ENDLOOP; WHILE fmin+delta <= fmax AND IsAll[[subMap.sampleMap, [smin, fmin], [smax-smin, delta]], background] DO fmin _ fmin+delta; ENDLOOP; ENDLOOP; RETURN [[subMap.sampleMap, [smin, fmin], [smax-smin, fmax-fmin]]] }; DumbTileBox: PROC [dest: SampleMap, start: CVEC, size: CVEC, source: SampleMap, s0, f0: INTEGER, phase: NAT, function: Function] ~ { FOR s: NAT IN [start.s..start.s+size.s) DO qr: QR ~ DivMod[(INTEGER[s]-s0), source.sSize]; fSource: CARDINAL _ Mod[INT[start.f]-f0 - QMul[qr.quotient, phase], source.fSize]; FOR f: NAT IN [start.f..start.f+size.f) DO sample: CARDINAL ~ GetSample[source, [qr.remainder, fSource]]; PutSample[dest, [s, f], sample, function]; fSource _ fSource + 1; IF fSource = source.fSize THEN fSource _ 0; ENDLOOP; ENDLOOP; }; EnlargedSize: PROC [fSize: NAT, bps: NAT] RETURNS [NAT] ~ { n: CARDINAL ~ ((smallWidth+fSize-1)/fSize+bps-1)/bps; RETURN [Basics.LongMult[n, fSize]] }; smallWidth: NAT _ 128; BoxProc: TYPE ~ SampleMapOps.BoxProc; TileBoxes: PUBLIC PROC [dest: SampleMap, boxes: PROC[BoxProc], source: SampleMap, s0, f0: INTEGER, phase: NAT, function: Function] ~ { sSize: NAT ~ dest.sSize; fSize: NAT ~ dest.fSize; bps: NAT ~ dest.bitsPerSample; MacroBrickAction: PROC [scratch: SampleMap] ~ { scratchBoxes: PROC[box: BoxProc] ~ {box[0, 0, scratch.sSize, scratch.fSize]}; GeneralTileBoxes[scratch, scratchBoxes, source, 0, 0, phase, [null, null]]; GeneralTileBoxes[dest, boxes, scratch, s0, f0, phase, function]; }; IF bps=source.bitsPerSample AND source.fSize*bps = bitsPerWord AND source.bitsPerLine = bitsPerWord AND source.sSize IN (0..16] AND phase = 0 AND source.base.bit = 0 AND function # [null, complement] THEN TRUSTED { bbTableSpace: PrincOps.BBTableSpace; bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace]; destBPL: CARDINAL ~ dest.bitsPerLine; easyBox: SAFE PROC [smin, fmin, smax, fmax: CARDINAL] ~ TRUSTED { dstBitIndex: LONG CARDINAL ~ dest.base.bit + Basics.LongMult[Check[smin, smax], destBPL] + Basics.LongMult[Check[fmin, fmax], bps]; yOffset: CARDINAL ~ LOOPHOLE[smin-s0, CARDINAL] MOD source.sSize; bb.dst _ IndexBit[dest.base.word, [lc[dstBitIndex]]]; bb.src.word _ source.base.word+yOffset; bb.src.bit _ LOOPHOLE[fmin-f0, CARDINAL] MOD 16; bb.srcDesc.gray.yOffset _ yOffset; bb.height _ Check[smax, sSize]-smin; bb.width _ Basics.LongMult[Check[fmax, fSize]-fmin, bps]; PrincOpsUtils.BITBLT[bb]; }; bb^ _ grayBitBltTable; bb.dstBpl _ dest.bitsPerLine; bb.srcDesc.gray.heightMinusOne _ source.sSize-1; bb.flags.srcFunc _ function.srcFunc; bb.flags.dstFunc _ function.dstFunc; boxes[easyBox]; RETURN }; IF bps#source.bitsPerSample OR source.fSize*bps < MIN[smallWidth, dest.fSize] THEN DoWithScratch[sSize: source.sSize, fSize: EnlargedSize[source.fSize, bps], bitsPerSample: bps, action: MacroBrickAction] ELSE GeneralTileBoxes[dest, boxes, source, s0, f0, phase, function]; }; QMul: PROC [a: INTEGER, b: CARDINAL] RETURNS [INT] ~ INLINE { IF a >= 0 THEN RETURN [LOOPHOLE[Basics.LongMult[a, b]]] ELSE RETURN [-LOOPHOLE[Basics.LongMult[-a, b], INT]] }; GeneralTileBoxes: PROC [dest: SampleMap, boxes: PROC[BoxProc], source: SampleMap, s0, f0: INTEGER, phase: NAT, function: Function] ~ { bps: NAT ~ dest.bitsPerSample; sSize: NAT ~ dest.sSize; fSize: NAT ~ dest.fSize; box: SAFE PROC [smin, fmin, smax, fmax: CARDINAL] ~ TRUSTED { sBrickSize: NAT ~ source.sSize; fBrickSize: NAT ~ source.fSize; qr: QR ~ DivMod[(INTEGER[smin]-s0), sBrickSize]; s: CARDINAL _ smin; sDelta: CARDINAL _ sBrickSize - qr.remainder; fSource: CARDINAL _ Mod[fmin-f0 - QMul[qr.quotient, phase], fBrickSize]; WHILE s < smax DO sBrick: NAT ~ sBrickSize-sDelta; sClipSize: NAT ~ MIN[sBrickSize+s, smax]-s; f: NAT _ fmin; fDelta: NAT _ fBrickSize-fSource; WHILE f < fmax DO Transfer[dest: dest, destStart: [s, f], source: [source, [sBrick, fBrickSize-fDelta], [sClipSize, MIN[fBrickSize+f, fmax]-f]], function: function]; f _ f + fDelta; fDelta _ fBrickSize; ENDLOOP; s _ s + sDelta; sDelta _ sBrickSize; WHILE fSource < phase DO fSource _ fSource + fBrickSize ENDLOOP; fSource _ fSource - phase; ENDLOOP; }; boxes[box]; }; Apply: PUBLIC PROC [dest, source: SampleMap, op: PROC [a, b: CARDINAL] RETURNS [CARDINAL]] ~ { fSize: NAT ~ MIN[dest.fSize, source.fSize]; a: Buffer ~ ObtainBuffer[fSize]; b: Buffer ~ ObtainBuffer[fSize]; FOR s: NAT IN [0..MIN[dest.sSize, source.sSize]) DO Get[buffer: a, sampleMap: dest, s: s]; Get[buffer: b, sampleMap: source, s: s]; FOR f: NAT IN [0..fSize) DO a[f] _ op[a[f],b[f]]; ENDLOOP; Put[buffer: a, sampleMap: dest, s: s, function: [null, null]]; ENDLOOP; ReleaseBuffer[a]; ReleaseBuffer[b]; }; Get: PUBLIC PROC [buffer: Buffer, start: NAT _ 0, count: NAT _ maxCount, sampleMap: SampleMap, s, f: NAT _ 0, ds: NAT _ 0, df: NAT _ 1] ~ TRUSTED { size: NAT ~ MIN[count, buffer.length-start]; IF size # 0 THEN { sSize: NAT ~ sampleMap.sSize; fSize: NAT ~ sampleMap.fSize; bpl: NAT ~ sampleMap.bitsPerLine; bps: NAT ~ sampleMap.bitsPerSample; bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace]; bbTableSpace: PrincOps.BBTableSpace; bufferPointer: LONG POINTER ~ InlineGetPointer[buffer, start, size]; srcBitIndex: LONG CARDINAL _ sampleMap.base.bit + Basics.LongMult[Basics.BoundsCheck[s, sSize], bpl] + Basics.LongMult[Basics.BoundsCheck[f, fSize], bps]; srcBitDelta: NAT ~ Basics.LongMult[ds, bpl] + Basics.LongMult[df, bps]; srcBitSkipDelta: NAT _ srcBitDelta; lgSkip: NAT _ 0; skipMinusOne: NAT _ 0; IF ds > 0 THEN [] _ Basics.BoundsCheck[s+Basics.LongMult[size-1, ds], sSize]; IF df > 0 THEN [] _ Basics.BoundsCheck[f+Basics.LongMult[size-1, df], fSize]; WHILE srcBitSkipDelta <= NAT.LAST/2 AND LOOPHOLE[srcBitSkipDelta, CARDINAL] MOD bitsPerWord # 0 DO srcBitSkipDelta _ srcBitSkipDelta * 2; lgSkip _ lgSkip + 1; ENDLOOP; skipMinusOne _ Shift[1, lgSkip]-1; PrincOpsUtils.LongZero[where: bufferPointer, nwords: size]; bb^ _ disjointBitBltTable; bb.dst.bit _ bitsPerWord-bps; bb.dstBpl _ Shift[bitsPerWord, lgSkip]; bb.srcDesc _ [srcBpl[srcBitSkipDelta]]; bb.width _ bps; FOR i: NAT IN [0..Shift[1, lgSkip]) DO bb.src _ IndexBit[sampleMap.base.word, [lc[srcBitIndex]]]; bb.height _ Shift[size-i+skipMinusOne, -lgSkip]; bb.dst.word _ bufferPointer+i; PrincOpsUtils.BITBLT[bb]; srcBitIndex _ srcBitIndex + srcBitDelta; ENDLOOP; PrincOpsUtils.BITBLT[bb]; }; }; Put: PUBLIC PROC [buffer: Buffer, start: NAT _ 0, count: NAT _ maxCount, sampleMap: SampleMap, s, f: NAT _ 0, ds: NAT _ 0, df: NAT _ 1, function: Function _ nullFunction] ~ TRUSTED { size: NAT ~ MIN[count, buffer.length-start]; IF size # 0 THEN { sSize: NAT ~ sampleMap.sSize; fSize: NAT ~ sampleMap.fSize; bpl: NAT ~ sampleMap.bitsPerLine; bps: NAT ~ sampleMap.bitsPerSample; bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace]; bbTableSpace: PrincOps.BBTableSpace; bufferPointer: LONG POINTER ~ InlineGetPointer[buffer, start, size]; dstBitIndex: LONG CARDINAL _ sampleMap.base.bit + Basics.LongMult[Basics.BoundsCheck[s, sSize], bpl] + Basics.LongMult[Basics.BoundsCheck[f, fSize], bps]; dstBitDelta: NAT _ Basics.LongMult[ds, bpl] + Basics.LongMult[df, bps]; dstBitSkipDelta: NAT _ dstBitDelta; lgSkip: NAT _ 0; skipMinusOne: NAT _ 0; bufferFirst: LONG POINTER _ bufferPointer; IF ds > 0 THEN [] _ Basics.BoundsCheck[s+Basics.LongMult[size-1, ds], sSize]; IF df > 0 THEN [] _ Basics.BoundsCheck[f+Basics.LongMult[size-1, df], fSize]; WHILE dstBitSkipDelta <= NAT.LAST/2 AND LOOPHOLE[dstBitSkipDelta, CARDINAL] MOD bitsPerWord # 0 DO dstBitSkipDelta _ dstBitSkipDelta * 2; lgSkip _ lgSkip + 1; ENDLOOP; skipMinusOne _ Shift[1, lgSkip]-1; bb^ _ disjointBitBltTable; bb.flags.srcFunc _ function.srcFunc; bb.flags.dstFunc _ function.dstFunc; bb.dstBpl _ dstBitSkipDelta; bb.src.bit _ bitsPerWord-bps; bb.srcDesc _ [srcBpl[Shift[bitsPerWord, lgSkip]]]; bb.width _ bps; FOR i: NAT IN [0..Shift[1, lgSkip]) DO bb.dst _ IndexBit[sampleMap.base.word, [lc[dstBitIndex]]]; bb.height _ Shift[size-i+skipMinusOne, -lgSkip]; bb.src.word _ bufferPointer+i; PrincOpsUtils.BITBLT[bb]; dstBitIndex _ dstBitIndex + dstBitDelta; ENDLOOP; }; }; Flip: PUBLIC PROC [buffer: Buffer] ~ TRUSTED { size: NAT ~ buffer.length; last: INTEGER ~ size-1; s: LONG POINTER TO Basics.RawWords ~ InlineGetPointer[buffer, 0, size]; k: NAT _ size; FOR j: NAT IN [0..size/2) DO t: CARDINAL _ s[j]; s[j] _ s[k _ k-1]; s[k] _ t; ENDLOOP; }; nScratchBuf: NAT ~ 6; scratchBuf: ARRAY [0..nScratchBuf) OF Buffer _ ALL[NIL]; ObtainBuffer: PUBLIC ENTRY PROC [length: NAT] RETURNS [Buffer] ~ { FOR i: NAT IN [0..nScratchBuf) DO buf: Buffer ~ scratchBuf[i]; IF buf # NIL AND buf.maxLength >= length THEN { scratchBuf[i] _ NIL; buf.length _ length; RETURN [buf]; }; ENDLOOP; RETURN [NEW[BufferRep[length] _ [length: length, samples:]]] }; ReleaseBuffer: PUBLIC ENTRY PROC [buffer: Buffer] ~ { r: Buffer _ buffer; buffer.length _ 0; FOR i: NAT IN [0..nScratchBuf) UNTIL r = NIL DO <> t: Buffer _ scratchBuf[i]; scratchBuf[i] _ r; r _ t; IF r = buffer THEN RETURN WITH ERROR MultipleReleaseOfScratch; ENDLOOP; }; InlineGetPointer: PROC [buffer: Buffer, start: NAT, count: NAT] RETURNS [LONG POINTER TO Basics.RawWords] ~ TRUSTED INLINE { [] _ Check[start+count, buffer.maxLength]; TRUSTED {RETURN [LOOPHOLE[buffer, LONG POINTER TO Basics.RawWords]+SIZE[BufferRep[start]]]} }; GetPointer: PUBLIC PROC [buffer: Buffer, start: NAT, count: NAT] RETURNS [LONG POINTER TO Basics.RawWords] ~ {RETURN [InlineGetPointer[buffer, start, count]]}; <> <> <> <> <> <> <<};>> <<>> END.