[prev in list] [next in list] [prev in thread] [next in thread]
List: squeak-vm-dev
Subject: [Vm-dev] VM Maker: VMMaker.oscog-nice.3251.mcz
From: commits () source ! squeak ! org
Date: 2022-08-25 16:09:20
Message-ID: E1oRFQG-0003FB-Ax () andreas
[Download RAW message or body]
[Attachment #2 (text/plain)]
Nicolas Cellier uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-nice.3251.mcz
==================== Summary ====================
Name: VMMaker.oscog-nice.3251
Author: nice
Time: 25 August 2022, 6:09:00.826995 pm
UUID: fad63ac4-33e9-944d-a688-a69c2b8f5b33
Ancestors: VMMaker.oscog-nice.3250
Implement a correctly rounded rgbMul BitBlt with the ideas developped here:
https://github.com/OpenSmalltalk/opensmalltalk-vm/issues/651
Also provide rgbMul tests for all depths (1 2 4 8 16 32)
(32 bits depth test = 8 bits depth test).
=============== Diff against VMMaker.oscog-nice.3250 ===============
Item was removed:
- ----- Method: BitBltSimulation>>partitionedMul:with:nBits:nPartitions: (in category \
'combination rules') -----
- partitionedMul: word1 with: word2 nBits: nBits nPartitions: nParts
- "Multiply word1 with word2 as nParts partitions of nBits each.
- This is useful for packed pixels, or packed colors.
- Bug in loop version when non-white background"
-
- | sMask product result dMask |
- "In C, integer multiplication might answer a wrong value if the unsigned values \
are declared as signed.
- This problem does not affect this method, because the most significant bit (i.e. \
the sign bit) will
- always be zero (jmv)"
- <returnTypeC: 'unsigned int'>
- <var: 'word1' type: #'unsigned int'>
- <var: 'word2' type: #'unsigned int'>
- <var: 'sMask' type: #'unsigned int'>
- <var: 'dMask' type: #'unsigned int'>
- <var: 'result' type: #'unsigned int'>
- <var: 'product' type: #'unsigned int'>
- sMask := maskTable at: nBits. "partition mask starts at the right"
- dMask := sMask << nBits.
- result := (((word1 bitAnd: sMask)+1) * ((word2 bitAnd: sMask)+1) - 1
- bitAnd: dMask) >> nBits. "optimized first step"
- nParts = 1
- ifTrue: [ ^result ].
- product := (((word1>>nBits bitAnd: sMask)+1) * ((word2>>nBits bitAnd: sMask)+1) - \
1 bitAnd: dMask).
- result := result bitOr: product.
- nParts = 2
- ifTrue: [ ^result ].
- product := (((word1>>(2*nBits) bitAnd: sMask)+1) * ((word2>>(2*nBits) bitAnd: \
sMask)+1) - 1 bitAnd: dMask).
- result := result bitOr: product << nBits.
- nParts = 3
- ifTrue: [ ^result ].
- product := (((word1>>(3*nBits) bitAnd: sMask)+1) * ((word2>>(3*nBits) bitAnd: \
sMask)+1) - 1 bitAnd: dMask).
- result := result bitOr: product << (2*nBits).
- ^ result
-
- " | sMask product result dMask |
- sMask := maskTable at: nBits. 'partition mask starts at the right'
- dMask := sMask << nBits.
- result := (((word1 bitAnd: sMask)+1) * ((word2 bitAnd: sMask)+1) - 1
- bitAnd: dMask) >> nBits. 'optimized first step'
- nBits to: nBits * (nParts-1) by: nBits do: [:ofs |
- product := (((word1>>ofs bitAnd: sMask)+1) * ((word2>>ofs bitAnd: sMask)+1) - 1 \
bitAnd: dMask).
- result := result bitOr: (product bitAnd: dMask) << (ofs-nBits)].
- ^ result"!
Item was added:
+ ----- Method: BitBltSimulation>>partitionedMul:with:nBits:wordBits: (in category \
'combination rules') ----- + partitionedMul: word1 with: word2 nBits: nBits wordBits: \
wordBits + "Multiply each channel of nBits in word1 and word2.
+ We assume that for each channel of nBits, we multiply ratios in interval [0..1], \
scaled by (1 << nBits - 1). + result := ((channel1/scale) * (channel2/scale) * \
scale) rounded + Or after simplification:
+ result := (channel1 * channel2 / scale) rounded
+ This is implemented by first forming the double precision products (channel1 * \
channel2) on a double-word. + Then dividing each double precision channel by scale, \
with correctly rounded operation. + With proper tricks, some of these operations can \
be multiplexed + (all channels are formed in parallel with a single sequence of \
operation)." +
+ | channelMask groupMask doubleGroupMask doubleWord1 doubleWord2 doubleWordMul half \
shift result highWordShift nGroups n2 | + <returnTypeC: 'unsigned int'>
+ <var: 'word1' type: #'unsigned int'>
+ <var: 'word2' type: #'unsigned int'>
+ <var: 'channelMask' type: #'unsigned int'>
+ <var: 'groupMask' type: #'unsigned int'>
+ <var: 'half' type: #'unsigned int'>
+ <var: 'doubleGroupMask' type: #'unsigned long long'>
+ <var: 'doubleWord1' type: #'unsigned long long'>
+ <var: 'doubleWord2' type: #'unsigned long long'>
+ <var: 'doubleWordMul' type: #'unsigned long long'>
+ <var: 'result' type: #'unsigned int'>
+ n2 := 2 * nBits. "width of double-precision channel"
+ channelMask := 1 << nBits - 1. "partition mask starts at the right"
+ nGroups := wordBits // nBits + 1 // 2. "number of channels that fit in a word, \
when alternating with group of zeros" + groupMask := channelMask. "form a word mask \
with alternate nBits 0 and nBits 1, so as to select even channels" + 2 to: nGroups \
do: [:i | groupMask := groupMask << n2 + channelMask]. + highWordShift := nGroups * \
n2. "shift for putting odd channels in high-word - usually wordBits, except if \
wordBits \\ nBits ~= 0" +
+ doubleWord1 := word1 >> nBits bitAnd: groupMask. "select odd channel interleaved \
with groups of nBits zeros, so as to leave room for double-precision multiplication" \
+ doubleWord2 := word2 >> nBits bitAnd: groupMask. + doubleWord1 := doubleWord1 << \
highWordShift + (word1 bitAnd: groupMask). "Put odd channels in high word, and even \
channels in low word" + doubleWord2 := doubleWord2 << highWordShift + (word2 bitAnd: \
groupMask). +
+ half := channelMask >> 1 + 1. "mid-value to add for getting a correctly rounded \
division" + shift := 0.
+ doubleWordMul := 0.
+ 1 to: wordBits // nBits do: [:i |
+ doubleWordMul := doubleWordMul + ((doubleWord1 >> shift bitAnd: channelMask) * \
(doubleWord2 >> shift bitAnd: channelMask) + half << shift). "multiply each channel \
of the two operands" + shift := shift + n2].
+
+ doubleGroupMask := groupMask. "form a mask for extracting single-precision \
channels in the double word" + doubleGroupMask := doubleGroupMask << highWordShift + \
groupMask. +
+ doubleWordMul := (doubleWordMul >> nBits bitAnd: doubleGroupMask) + doubleWordMul \
>> nBits bitAnd: doubleGroupMask. "divide by scale" + result := doubleWordMul >> \
> > (highWordShift - nBits) + (doubleWordMul bitAnd: groupMask). "compact channels \
> > back into a single word"
+ ^result!
Item was changed:
----- Method: BitBltSimulation>>rgbMul:with: (in category 'combination rules') \
----- rgbMul: sourceWord with: destinationWord
<inline: false>
<returnTypeC: 'unsigned int'>
<var: 'sourceWord' type: #'unsigned int'>
<var: 'destinationWord' type: #'unsigned int'>
destDepth < 16 ifTrue:
["Mul each pixel separately"
+ destDepth = 1 ifTrue: [^self bitAnd: sourceWord with: destinationWord].
+ ^ self partitionedMul: sourceWord with: destinationWord nBits: destDepth \
wordBits: 32].
- ^ self partitionedMul: sourceWord with: destinationWord
- nBits: destDepth nPartitions: destPPW].
destDepth = 16 ifTrue:
["Mul RGB components of each pixel separately"
+ ^ (self partitionedMul: (sourceWord bitAnd: 16rFFFF) with: (destinationWord \
bitAnd: 16rFFFF) nBits: 5 wordBits: 16) + + ((self partitionedMul: sourceWord>>16 \
with: destinationWord>>16 nBits: 5 wordBits: 16) << 16)]
- ^ (self partitionedMul: sourceWord with: destinationWord
- nBits: 5 nPartitions: 3)
- + ((self partitionedMul: sourceWord>>16 with: destinationWord>>16
- nBits: 5 nPartitions: 3) << 16)]
ifFalse:
["Mul RGBA components of the pixel separately"
+ ^ self partitionedMul: sourceWord with: destinationWord nBits: 8 wordBits: 32]!
- ^ self partitionedMul: sourceWord with: destinationWord
- nBits: 8 nPartitions: 4]
-
- " | scanner |
- Display repaintMorphicDisplay.
- scanner := DisplayScanner quickPrintOn: Display.
- MessageTally time: [0 to: 760 by: 4 do: [:y |scanner drawString: \
'qwrepoiuasfd=)(/&()=#!!lkjzxv.,mn124+09857907QROIYTOAFDJZXNBNB,M-.,Mqwrepoiuasfd=)(/&()=#!!lkjzxv.,mn124+09857907QROIYTOAFDJZXNBNB,M-.,M1234124356785678' \
at: 0@y]]. "!
Item was added:
+ ----- Method: BitBltSimulationTest>>testRgbMulDepth16 (in category 'tests') -----
+ testRgbMulDepth16
+ | x f1 f2 f3 bb |
+ x := 1 << 5.
+ f1 := Form extent: x@x depth: 16.
+ f2 := Form extent: x@x depth: 16.
+ 0 to: x-1 do: [:ix |
+ 0 to: x-1 do: [:iy |
+ f1 pixelValueAt: ix@iy put: ((ix bitOr: ix+10\\x<<5) bitOr: ix+20\\x<<10).
+ f2 pixelValueAt: ix@iy put: ((iy bitOr: iy+10\\x<<5) bitOr: iy+20\\x<<10)]].
+ f3 := f2 copy.
+ bb := BitBlt new.
+ bb setDestForm: f3; sourceForm: f1.
+ bb sourceX: 0; sourceY: 0; destX: 0; destY: 0.
+ bb width: x; height: x.
+ bb combinationRule: Form rgbMul.
+ bb copyBits.
+ 0 to: x-1 do: [:ix |
+ 0 to: x-1 do: [:iy |
+ "Test that each 5 bits rgb channel is correctly rounded multiplication"
+ self assert: ((f3 pixelValueAt: ix@iy) >> 10 bitAnd: 31)
+ = (((f1 pixelValueAt: ix@iy) >> 10 bitAnd: 31)
+ * ((f2 pixelValueAt: ix@iy) >>10 bitAnd: 31) / (x - 1)) rounded.
+ self assert: ((f3 pixelValueAt: ix@iy) >> 5 bitAnd: 31)
+ = (((f1 pixelValueAt: ix@iy) >> 5 bitAnd: 31)
+ * ((f2 pixelValueAt: ix@iy) >>5 bitAnd: 31) / (x - 1)) rounded.
+ self assert: ((f3 pixelValueAt: ix@iy) bitAnd: 31)
+ = (((f1 pixelValueAt: ix@iy) bitAnd: 31)
+ * ((f2 pixelValueAt: ix@iy) bitAnd: 31) / (x - 1)) rounded]]!
Item was added:
+ ----- Method: BitBltSimulationTest>>testRgbMulDepth1to8 (in category 'tests') -----
+ testRgbMulDepth1to8
+ "Note that depth=32 and depth=8 have exactly same effect 32bits-word-wise
+ since we decompose 32 bits depth in four 8-bits channels, ARGB.
+ Only depth 16 is special, with 3 channels of 5 bits, and 1 dead bit."
+ #(1 2 4 8) do: [:d |
+ | x f1 f2 f3 bb |
+ x := 1 << d.
+ f1 := Form extent: x@x depth: d.
+ f2 := Form extent: x@x depth: d.
+ 0 to: x-1 do: [:ix |
+ 0 to: x-1 do: [:iy |
+ f1 pixelValueAt: ix@iy put: ix.
+ f2 pixelValueAt: ix@iy put: iy]].
+ f3 := f2 copy.
+ bb := BitBlt new.
+ bb setDestForm: f3; sourceForm: f1.
+ bb sourceX: 0; sourceY: 0; destX: 0; destY: 0.
+ bb width: x; height: x.
+ bb combinationRule: Form rgbMul.
+ bb copyBits.
+ 0 to: x-1 do: [:ix |
+ 0 to: x-1 do: [:iy |
+ self assert: (f3 pixelValueAt: ix@iy) = ((f1 pixelValueAt: ix@iy) * (f2 \
pixelValueAt: ix@iy) / (x - 1)) rounded]]]!
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic