<div dir="ltr"><div>Finally :-D</div><div><br></div><div>Best,</div><div>Karl</div><div><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, Dec 23, 2020 at 9:55 PM <<a href="mailto:commits@source.squeak.org">commits@source.squeak.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"> <br>
Nicolas Cellier uploaded a new version of VMMaker to project VM Maker:<br>
<a href="http://source.squeak.org/VMMaker/VMMaker.oscog-nice.2909.mcz" rel="noreferrer" target="_blank">http://source.squeak.org/VMMaker/VMMaker.oscog-nice.2909.mcz</a><br>
<br>
==================== Summary ====================<br>
<br>
Name: VMMaker.oscog-nice.2909<br>
Author: nice<br>
Time: 23 December 2020, 9:54:51.201058 pm<br>
UUID: 6869c4f1-9d80-40c3-8409-7c05e087edf5<br>
Ancestors: VMMaker.oscog-eem.2908<br>
<br>
WIP: implement new BitBlt ops (rules) for alpha compositing<br>
<br>
                "42" alphaScale:with:<br>
                "43" alphaUnscale:with:<br>
                "44" alphaBlendUnscaled:with:<br>
<br>
This is a proposal implementation for <a href="https://github.com/OpenSmalltalk/opensmalltalk-vm/issues/505" rel="noreferrer" target="_blank">https://github.com/OpenSmalltalk/opensmalltalk-vm/issues/505</a><br>
<br>
The generated C code compiles, but it's otherwise mostly yet unused and untested code. I commit it before I loose it.<br>
There's probably more to do for letting accelerated code work (PI).<br>
<br>
=============== Diff against VMMaker.oscog-eem.2908 ===============<br>
<br>
Item was changed:<br>
  SmartSyntaxInterpreterPlugin subclass: #BitBltSimulation<br>
        instanceVariableNames: 'destForm sourceForm halftoneForm combinationRule destX destY width height sourceX sourceY clipX clipY clipWidth clipHeight sourceWidth sourceHeight sourceDepth sourcePitch sourceBits sourcePPW sourceMSB destWidth destHeight destDepth destPitch destBits destPPW destMSB bitCount skew mask1 mask2 preload nWords destMask hDir vDir sourceIndex sourceDelta destIndex destDelta sx sy dx dy bbW bbH halftoneHeight noSource noHalftone halftoneBase sourceAlpha srcBitShift dstBitShift bitBltOop affectedL affectedR affectedT affectedB opTable maskTable ditherMatrix4x4 ditherThresholds16 ditherValues16 hasSurfaceLock warpSrcShift warpSrcMask warpAlignShift warpAlignMask warpBitShiftTable querySurfaceFn lockSurfaceFn unlockSurfaceFn isWarping cmFlags cmMask cmShiftTable cmMaskTable cmLookupTable cmBitsPerColor dither8Lookup componentAlphaModeColor componentAlphaModeAlpha ungammaLookupTable gammaLookupTable numGCsOnInvocation bitBltIsReceiver endOfDestination endOfSource'<br>
        classVariableNames: 'AllOnes AlphaIndex BBClipHeightIndex BBClipWidthIndex BBClipXIndex BBClipYIndex BBColorMapIndex BBDestFormIndex BBDestXIndex BBDestYIndex BBHalftoneFormIndex BBHeightIndex BBLastIndex BBRuleIndex BBSourceFormIndex BBSourceXIndex BBSourceYIndex BBWarpBase BBWidthIndex BBXTableIndex BEBitBltIndex BinaryPoint BlueIndex ColorMapFixedPart ColorMapIndexedPart ColorMapNewStyle ColorMapPresent CrossedX EndOfRun FixedPt1 FormBitsIndex FormDepthIndex FormHeightIndex FormWidthIndex GreenIndex OpTable OpTableSize RedIndex'<br>
        poolDictionaries: ''<br>
        category: 'VMMaker-Interpreter'!<br>
<br>
+ !BitBltSimulation commentStamp: 'nice 10/31/2020 23:39' prior: 0!<br>
- !BitBltSimulation commentStamp: 'tpr 3/25/2013 16:50' prior: 0!<br>
  This class implements BitBlt, much as specified in the Blue Book spec.<br>
<br>
  Performance has been enhanced through the use of pointer variables such as sourceIndex and destIndex, and by separating several special cases of the inner loop.<br>
<br>
  Operation has been extended to color, with support for 1, 2, 4, 8, 16, and 32-bit pixel sizes.  Conversion between different pixel sizes is facilitated by accepting an optional color map.<br>
<br>
  In addition to the original 16 combination rules, this BitBlt supports<br>
        16      fail (for old paint mode)<br>
        17      fail (for old mask mode)<br>
        18      sourceWord + destinationWord<br>
        19      sourceWord - destinationWord<br>
        20      rgbAdd: sourceWord with: destinationWord<br>
        21      rgbSub: sourceWord with: destinationWord<br>
        22      OLDrgbDiff: sourceWord with: destinationWord<br>
        23      OLDtallyIntoMap: destinationWord -- old vers doesn't clip to bit boundary<br>
        24      alphaBlend: sourceWord with: destinationWord<br>
        25      pixPaint: sourceWord with: destinationWord<br>
        26      pixMask: sourceWord with: destinationWord<br>
        27      rgbMax: sourceWord with: destinationWord<br>
        28      rgbMin: sourceWord with: destinationWord<br>
        29      rgbMin: sourceWord bitInvert32 with: destinationWord<br>
        30      alphaBlendConst: sourceWord with: destinationWord -- alpha passed as an arg<br>
        31      alphaPaintConst: sourceWord with: destinationWord -- alpha passed as an arg<br>
        32      rgbDiff: sourceWord with: destinationWord<br>
        33      tallyIntoMap: destinationWord<br>
        34      alphaBlendScaled: sourceWord with: destinationWord<br>
        35 alphaBlendScaled: sourceWord with:   "unused here - only used by FXBlt"<br>
        36 alphaBlendScaled: sourceWord with:   "unused here - only used by FXBlt"<br>
        37 rgbMul: sourceWord with: destinationWord<br>
        38 pixSwap: sourceWord with: destinationWord<br>
        39 pixClear: sourceWord with: destinationWord<br>
        40 fixAlpha: sourceWord with: destinationWord<br>
        41 rgbComponentAlpha: sourceWord with: destinationWord<br>
+       42 alphaScale: ignoredSourceWord with: destinationWord<br>
+       43 alphaUnscale: ignoredSourceWord with: destinationWord<br>
+       44      alphaBlendUnscaled: sourceWord with: destinationWord<br>
<br>
  This implementation has also been fitted with an experimental "warp drive" that allows abritrary scaling and rotation (and even limited affine deformations) with all BitBlt storage modes supported.<br>
<br>
  To add a new rule to BitBlt...<br>
        1.  add the new rule method or methods in the category 'combination rules' of BBSim<br>
        2.  describe it in the class comment  of BBSim and in the class comment for BitBlt<br>
        3.  add refs to initializeRuleTable in proper positions<br>
        4.  add refs to initBBOpTable, following the pattern<br>
  !<br>
<br>
Item was changed:<br>
  ----- Method: BitBltSimulation class>>initializeRuleTable (in category 'initialization') -----<br>
  initializeRuleTable<br>
        "BitBltSimulation initializeRuleTable"<br>
        "**WARNING** You MUST change initBBOpTable if you change this"<br>
        OpTable := #(<br>
                "0" clearWord:with:<br>
                "1" bitAnd:with:<br>
                "2" bitAndInvert:with:<br>
                "3" sourceWord:with:<br>
                "4" bitInvertAnd:with:<br>
                "5" destinationWord:with:<br>
                "6" bitXor:with:<br>
                "7" bitOr:with:<br>
                "8" bitInvertAndInvert:with:<br>
                "9" bitInvertXor:with:<br>
                "10" bitInvertDestination:with:<br>
                "11" bitOrInvert:with:<br>
                "12" bitInvertSource:with:<br>
                "13" bitInvertOr:with:<br>
                "14" bitInvertOrInvert:with:<br>
                "15" destinationWord:with:<br>
                "16" destinationWord:with: "unused - was old paint"<br>
                "17" destinationWord:with: "unused - was old mask"<br>
                "18" addWord:with:<br>
                "19" subWord:with:<br>
                "20" rgbAdd:with:<br>
                "21" rgbSub:with:<br>
                "22" OLDrgbDiff:with:<br>
                "23" OLDtallyIntoMap:with:<br>
                "24" alphaBlend:with:<br>
                "25" pixPaint:with:<br>
                "26" pixMask:with:<br>
                "27" rgbMax:with:<br>
                "28" rgbMin:with:<br>
                "29" rgbMinInvert:with:<br>
                "30" alphaBlendConst:with:<br>
                "31" alphaPaintConst:with:<br>
                "32" rgbDiff:with:<br>
                "33" tallyIntoMap:with:<br>
                "34" alphaBlendScaled:with:<br>
<br>
                "35" alphaBlendScaled:with:     "unused here - only used by FXBlt"<br>
                "36" alphaBlendScaled:with:     "unused here - only used by FXBlt"<br>
                "37" rgbMul:with:<br>
                "38" pixSwap:with:<br>
                "39" pixClear:with:<br>
                "40" fixAlpha:with:<br>
                "41" rgbComponentAlpha:with:<br>
+               "42" alphaScale:with:<br>
+               "43" alphaUnscale:with:<br>
+               "44" alphaBlendUnscaled:with:<br>
        ).<br>
        OpTableSize := OpTable size + 1.  "0-origin indexing"<br>
  !<br>
<br>
Item was added:<br>
+ ----- Method: BitBltSimulation>>alphaBlendUnscaled:with: (in category 'combination rules') -----<br>
+ alphaBlendUnscaled: sourceWord with: destinationWord<br>
+       "Blend sourceWord with destinationWord using the alpha value from both sourceWord and destinationWord.<br>
+       Alpha is encoded as 0 meaning 0.0, and 255 meaning 1.0.<br>
+       The alpha channel and color produced are<br>
+ <br>
+               srcAlpha + (destAlpha*(1-srcAlpha))<br>
+               (srcAlpha*srcColor + (destAlpha*(1-srcAlpha)*dstColor)) / (srcAlpha + (destAlpha*(1-srcAlpha)))<br>
+ <br>
+       In contrast to alphaBlend:with: the method does not assume that destination form is opaque.<br>
+       In contrast to alphaBlendScaled:with: the method does not assume that colors have been pre-scaled (muliplied) by alpha channel."<br>
+       | alpha blendA result blendRB blendG |<br>
+       <inline: false><br>
+       <returnTypeC: 'unsigned int'><br>
+       <var: #sourceWord type: 'unsigned int'><br>
+       <var: #destinationWord type: 'unsigned int'><br>
+       <var: #blendRB type: 'unsigned int'><br>
+       <var: #blendG type: 'unsigned int'><br>
+       <var: #result type: 'unsigned int'><br>
+       <var: #alpha type: 'unsigned int'><br>
+       <var: #blendA type: 'unsigned int'><br>
+       alpha := sourceWord >> 24.  "High 8 bits of source pixel, assuming ARGB encoding"<br>
+       alpha = 0 ifTrue: [ ^ destinationWord ].<br>
+       alpha = 255 ifTrue: [ ^ sourceWord ].<br>
+       <br>
+       blendA := 16rFF * alpha + (16rFF - alpha * (destinationWord >> 24)) + 16rFF. "blend alpha channels"<br>
+       blendA := blendA + (blendA - 1 >> 8 bitAnd: 16rFF) >> 8 bitAnd: 16rFF. "divide by 255"<br>
+ <br>
+       blendRB := ((sourceWord bitAnd: 16rFF00FF) * alpha) +<br>
+                               ((destinationWord bitAnd: 16rFF00FF) * (blendA-alpha))<br>
+                               / blendA.       "blend red and blue"<br>
+ <br>
+       blendG := ((sourceWord bitAnd: 16r00FF00) * alpha) +<br>
+                               ((destinationWord bitAnd: 16r00FF00) * (blendA-alpha))<br>
+                               / blendA.       "blend green"<br>
+       result := (blendRB bitOr: blendG) bitOr: blendA << 24.<br>
+       ^ result<br>
+ !<br>
<br>
Item was added:<br>
+ ----- Method: BitBltSimulation>>alphaScale:with: (in category 'combination rules') -----<br>
+ alphaScale: sourceWord with: destinationWord<br>
+       "Scale (premultiply) the destination with its alpha channel.<br>
+       Note that sourceWord is ignored."<br>
+       | alpha rb g |<br>
+       <inline: false> "Do NOT inline this into optimized loops"<br>
+       <returnTypeC: 'unsigned int'><br>
+       <var: #sourceWord type: 'unsigned int'><br>
+       <var: #destinationWord type: 'unsigned int'><br>
+       <var: #rb type: 'unsigned int'><br>
+       <var: #g type: 'unsigned int'><br>
+       <var: #alpha type: 'unsigned int'><br>
+       alpha := destinationWord >> 24.  "High 8 bits is opacity (ARGB format)"<br>
+       rb := ((destinationWord bitAnd: 16rFF00FF) * alpha >> 8 bitAnd: 16rFF00FF). "scale red and blue components"<br>
+       g := ((destinationWord bitAnd: 16r00FF00) * alpha >> 8 bitAnd: 16r00FF00). "scale green component"<br>
+       ^(g bitOr: rb) bitOr: (destinationWord bitAnd: 16rFF000000) "recompose"!<br>
<br>
Item was added:<br>
+ ----- Method: BitBltSimulation>>alphaUnscale:with: (in category 'combination rules') -----<br>
+ alphaUnscale: sourceWord with: destinationWord<br>
+       "Unscale (divide) the destination with its alpha channel.<br>
+       Note that sourceWord is ignored."<br>
+       | alpha rb g rgb carry |<br>
+       <inline: false> "Do NOT inline this into optimized loops"<br>
+       <returnTypeC: 'unsigned int'><br>
+       <var: #sourceWord type: 'unsigned int'><br>
+       <var: #destinationWord type: 'unsigned int'><br>
+       <var: #rb type: 'unsigned int'><br>
+       <var: #g type: 'unsigned int'><br>
+       <var: #rgb type: 'unsigned int'><br>
+       <var: #alpha type: 'unsigned int'><br>
+       <var: #carry type: 'unsigned int'><br>
+       alpha := destinationWord >> 24.  "High 8 bits is opacity (ARGB format)"<br>
+       alpha = 0 ifTrue: [^0].<br>
+       rb := (destinationWord bitAnd: 16rFF00FF) << 8 / alpha. "unscale red and blue components"<br>
+       g := (destinationWord bitAnd: 16r00FF00) / alpha. "unscale green component"<br>
+       carry := ((rb >> 8 bitAnd: 16rAA00AA) >> 1 bitOr: (rb >> 8 bitAnd: 16r550055) << 1)<br>
+               bitOr: ((g bitAnd: 16r00AA00) >> 1 bitOr: (g bitAnd: 16r005500) << 1).<br>
+       carry := (carry bitAnd: 16rCCCCCC) >> 2 bitOr: (carry bitAnd: 16r333333) << 2.<br>
+       carry := (carry bitAnd: 16rF0F0F0) >> 4 bitOr: (carry bitAnd: 16r0F0F0F) << 4.<br>
+       rgb := (rb bitAnd: 16rFF00FF) bitOr: (g << 8 bitAnd: 16r00FF00).<br>
+       rgb := rgb bitOr: carry.  "saturate RGB components if division overflows"<br>
+       ^rgb bitOr: (destinationWord bitAnd: 16rFF000000) "restore alpha"!<br>
<br>
Item was changed:<br>
  ----- Method: BitBltSimulation>>initBBOpTable (in category 'initialize-release') -----<br>
  initBBOpTable<br>
        self cCode: 'opTable[0+1] = (void *)clearWordwith'.<br>
        self cCode: 'opTable[1+1] = (void *)bitAndwith'.<br>
        self cCode: 'opTable[2+1] = (void *)bitAndInvertwith'.<br>
        self cCode: 'opTable[3+1] = (void *)sourceWordwith'.<br>
        self cCode: 'opTable[4+1] = (void *)bitInvertAndwith'.<br>
        self cCode: 'opTable[5+1] = (void *)destinationWordwith'.<br>
        self cCode: 'opTable[6+1] = (void *)bitXorwith'.<br>
        self cCode: 'opTable[7+1] = (void *)bitOrwith'.<br>
        self cCode: 'opTable[8+1] = (void *)bitInvertAndInvertwith'.<br>
        self cCode: 'opTable[9+1] = (void *)bitInvertXorwith'.<br>
        self cCode: 'opTable[10+1] = (void *)bitInvertDestinationwith'.<br>
        self cCode: 'opTable[11+1] = (void *)bitOrInvertwith'.<br>
        self cCode: 'opTable[12+1] = (void *)bitInvertSourcewith'.<br>
        self cCode: 'opTable[13+1] = (void *)bitInvertOrwith'.<br>
        self cCode: 'opTable[14+1] = (void *)bitInvertOrInvertwith'.<br>
        self cCode: 'opTable[15+1] = (void *)destinationWordwith'.<br>
        self cCode: 'opTable[16+1] = (void *)destinationWordwith'.<br>
        self cCode: 'opTable[17+1] = (void *)destinationWordwith'.<br>
        self cCode: 'opTable[18+1] = (void *)addWordwith'.<br>
        self cCode: 'opTable[19+1] = (void *)subWordwith'.<br>
        self cCode: 'opTable[20+1] = (void *)rgbAddwith'.<br>
        self cCode: 'opTable[21+1] = (void *)rgbSubwith'.<br>
        self cCode: 'opTable[22+1] = (void *)OLDrgbDiffwith'.<br>
        self cCode: 'opTable[23+1] = (void *)OLDtallyIntoMapwith'.<br>
        self cCode: 'opTable[24+1] = (void *)alphaBlendwith'.<br>
        self cCode: 'opTable[25+1] = (void *)pixPaintwith'.<br>
        self cCode: 'opTable[26+1] = (void *)pixMaskwith'.<br>
        self cCode: 'opTable[27+1] = (void *)rgbMaxwith'.<br>
        self cCode: 'opTable[28+1] = (void *)rgbMinwith'.<br>
        self cCode: 'opTable[29+1] = (void *)rgbMinInvertwith'.<br>
        self cCode: 'opTable[30+1] = (void *)alphaBlendConstwith'.<br>
        self cCode: 'opTable[31+1] = (void *)alphaPaintConstwith'.<br>
        self cCode: 'opTable[32+1] = (void *)rgbDiffwith'.<br>
        self cCode: 'opTable[33+1] = (void *)tallyIntoMapwith'.<br>
        self cCode: 'opTable[34+1] = (void *)alphaBlendScaledwith'.<br>
        self cCode: 'opTable[35+1] = (void *)alphaBlendScaledwith'.<br>
        self cCode: 'opTable[36+1] = (void *)alphaBlendScaledwith'.     <br>
        self cCode: 'opTable[37+1] = (void *)rgbMulwith'.<br>
        self cCode: 'opTable[38+1] = (void *)pixSwapwith'.<br>
        self cCode: 'opTable[39+1] = (void *)pixClearwith'.<br>
        self cCode: 'opTable[40+1] = (void *)fixAlphawith'.<br>
+       self cCode: 'opTable[41+1] = (void *)rgbComponentAlphawith'.<br>
+       self cCode: 'opTable[42+1] = (void *)alphaScalewith'.<br>
+       self cCode: 'opTable[43+1] = (void *)alphaUnscalewith'.<br>
+       self cCode: 'opTable[44+1] = (void *)alphaBlendUnscaledwith'.!<br>
-       self cCode: 'opTable[41+1] = (void *)rgbComponentAlphawith'.!<br>
<br>
</blockquote></div>