In addition to the existing alpha blending rules (24 and 34), I propose 3 new additional rules.
Check https://en.wikipedia.org/wiki/Alpha_compositing
Existing rule 34 is a correct implementation of Alpha Blending for scaled forms, i.e. if premultiplied alpha is used. But rule 24 is a correct implementation of non-scaled forms, only for the case where destination is opaque (i.e. it's alpha is 1.0 in every pixel). If destination includes translucency (or it is completely transparent), the result is not correct. In order to fix it, the RGB of each pixel need to be divided by the pixel alpha.
The proposed blendUnscaled is the basic (for non-scaled forms) alpha blending described in Wikipedia. Note that users knowing that destination background is opaque might call the faster rule 24 instead.
The other two additional proposed rules are for converting to and from premultiplied alpha.
EXISTING blend 24 alphaBlend
resultAlpha = srcAlpha + destAlpha*(1-srcAlpha)
resultRGB = srcAlpha*source + (1-srcAlpha)*dest
EXISTING blendAlphaScaled 34 alphaBlendScaled
resultRGBA = source + (1-srcAlpha)*dest
NEW PROPOSED multiplyRGBByAlpha
Non premultiplied alpha -> premultiplied alpha. Only uses destination. Alpha unmodified. For each RGB component,
resultRGB = dest*destAlpha
NEW PROPOSED divideRGBByAlpha
Premultiplied alpha -> non premultiplied alpha. Only uses destination. Alpha unmodified. For each RGB component,
resultRGB = dest/destAlpha
NEW PROPOSED blendUnscaled
Equivalent to blend, and then divideRGBByAlpha
resultAlpha = srcAlpha + destAlpha*(1-srcAlpha)
resultRGB = (srcAlpha*source + (1-srcAlpha)*dest) / resultAlpha
This would allow handling of scaled (premultiplied-alpha) forms, and blending of regular forms including translucency, without the need to call slower smalltalk code to fix the results.
--
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/OpenSmalltalk/opensmalltalk-vm/issues/505
Branch: refs/heads/Cog
Home: https://github.com/OpenSmalltalk/opensmalltalk-vm
Commit: 496034f6c2caec4a8a25d86f3221a95bae478979
https://github.com/OpenSmalltalk/opensmalltalk-vm/commit/496034f6c2caec4a8a…
Author: Eliot Miranda <eliot.miranda(a)gmail.com>
Date: 2022-02-25 (Fri, 25 Feb 2022)
Changed paths:
M platforms/Cross/vm/sqAtomicOps.h
M platforms/iOS/vm/Common/Classes/sqSqueakMainApp.m
M src/plugins/HostWindowPlugin/HostWindowPlugin.c
M src/plugins/IA32ABI/IA32ABI.c
M src/plugins/SqueakFFIPrims/ARM32FFIPlugin.c
M src/plugins/SqueakFFIPrims/ARM64FFIPlugin.c
M src/plugins/SqueakFFIPrims/IA32FFIPlugin.c
M src/plugins/SqueakFFIPrims/X64SysVFFIPlugin.c
M src/plugins/SqueakFFIPrims/X64Win64FFIPlugin.c
M src/spur32.cog.lowcode/cogit.h
M src/spur32.cog.lowcode/cogitARMv5.c
M src/spur32.cog.lowcode/cogitIA32.c
M src/spur32.cog.lowcode/cointerp.c
M src/spur32.cog.lowcode/cointerp.h
M src/spur32.cog.lowcode/gcc3x-cointerp.c
M src/spur32.cog/cogit.h
M src/spur32.cog/cogitARMv5.c
M src/spur32.cog/cogitIA32.c
M src/spur32.cog/cointerp.c
M src/spur32.cog/cointerp.h
M src/spur32.cog/cointerpmt.c
M src/spur32.cog/cointerpmt.h
M src/spur32.cog/gcc3x-cointerp.c
M src/spur32.cog/gcc3x-cointerpmt.c
M src/spur32.sista/cogit.h
M src/spur32.sista/cogitARMv5.c
M src/spur32.sista/cogitIA32.c
M src/spur32.sista/cointerp.c
M src/spur32.sista/cointerp.h
M src/spur32.sista/gcc3x-cointerp.c
M src/spur32.stack.lowcode/gcc3x-interp.c
M src/spur32.stack.lowcode/interp.c
M src/spur32.stack/gcc3x-interp.c
M src/spur32.stack/interp.c
M src/spur32.stack/validImage.c
M src/spur64.cog.lowcode/cogit.h
M src/spur64.cog.lowcode/cogitARMv8.c
M src/spur64.cog.lowcode/cogitX64SysV.c
M src/spur64.cog.lowcode/cogitX64WIN64.c
M src/spur64.cog.lowcode/cointerp.c
M src/spur64.cog.lowcode/cointerp.h
M src/spur64.cog.lowcode/gcc3x-cointerp.c
M src/spur64.cog/cogit.h
M src/spur64.cog/cogitARMv8.c
M src/spur64.cog/cogitX64SysV.c
M src/spur64.cog/cogitX64WIN64.c
M src/spur64.cog/cointerp.c
M src/spur64.cog/cointerp.h
M src/spur64.cog/cointerpmt.c
M src/spur64.cog/cointerpmt.h
M src/spur64.cog/gcc3x-cointerp.c
M src/spur64.cog/gcc3x-cointerpmt.c
M src/spur64.sista/cogit.h
M src/spur64.sista/cogitARMv8.c
M src/spur64.sista/cogitX64SysV.c
M src/spur64.sista/cogitX64WIN64.c
M src/spur64.sista/cointerp.c
M src/spur64.sista/cointerp.h
M src/spur64.sista/gcc3x-cointerp.c
M src/spur64.stack.lowcode/gcc3x-interp.c
M src/spur64.stack.lowcode/interp.c
M src/spur64.stack/gcc3x-interp.c
M src/spur64.stack/interp.c
M src/spur64.stack/validImage.c
M src/v3.cog/cogit.h
M src/v3.cog/cogitARMv5.c
M src/v3.cog/cogitIA32.c
M src/v3.cog/cointerp.c
M src/v3.cog/cointerp.h
M src/v3.cog/gcc3x-cointerp.c
M src/v3.stack/gcc3x-interp.c
M src/v3.stack/interp.c
Log Message:
-----------
CogVM source as per Name: VMMaker.oscog-eem.3172
Increase the stack page heradroom on Apple ARMv8 systems. Experience with
Virtend shows more headroom than ~ 1k bytes is needed. Now it's ~ 6k bytes
with an 8k byte page size, up from a 4k byet page.
Access CogStackPages>>bytesPerPage directly for vmParameterAt:
Eliminate several incompatible pointer warnings.
Fix warnings in sqExternalSemaphores.c on WIN64 with the MSVC toolchain by
suitable casts of InterlockedAdd[64] & InterlockedCompareExchange[64] args.
Branch: refs/heads/Cog
Home: https://github.com/OpenSmalltalk/opensmalltalk-vm
Commit: 41e16daa6bde22ca494f1a9935f8d1f345036323
https://github.com/OpenSmalltalk/opensmalltalk-vm/commit/41e16daa6bde22ca49…
Author: Eliot Miranda <eliot.miranda(a)gmail.com>
Date: 2022-02-25 (Fri, 25 Feb 2022)
Changed paths:
M platforms/Mac OS/vm/sqMacMain.c
M platforms/iOS/vm/Common/Classes/sqSqueakMainApp.m
M platforms/minheadless/unix/sqPlatformSpecific-Unix.c
M platforms/minheadless/windows/sqPlatformSpecific-Win32.c
M platforms/unix/vm/sqUnixMain.c
M platforms/win32/vm/sqWin32Main.c
Log Message:
-----------
Fix getRedzoneSize which in most cases was underestimating (by a small ammount)
the distance between stack handler and signaller.
Branch: refs/heads/Cog
Home: https://github.com/OpenSmalltalk/opensmalltalk-vm
Commit: f77943115bbb8e55fc1adeaf54f483ecc6024bc6
https://github.com/OpenSmalltalk/opensmalltalk-vm/commit/f77943115bbb8e55fc…
Author: Eliot Miranda <eliot.miranda(a)gmail.com>
Date: 2022-02-24 (Thu, 24 Feb 2022)
Changed paths:
M src/plugins/BitBltPlugin/BitBltPlugin.c
Log Message:
-----------
CogVM source as per VMMaker.oscog-nice.3170/eem.3171
BitBltPlugin:
Revise the 3 new BitBlt rules again
(see https://github.com/OpenSmalltalk/opensmalltalk-vm/issues/505)
- use a proper division by 255 (factor alpha/255) in alphaScale:with: instead of approximate factor alpha/256 previously
- use a proper rounding (by adding 16r80 before the division by 255) in alphaScale:with:
- split the unscale ops in 3 separate r/g/b channels, otherwise, when grouping rb, the division by alpha will leak red bits not only on green components but also on blue
- fixup the carry used for saturating the rbg components in case of 16rFF overflow in alphaUnscale:with:
Note: division by 255 can be checked thru this snippet (should answer 0):
(0 to: 16rFF squared) inject: 0 into:
[:max :num |
| rat |
rat := num + 16r80. "+ 16r80 for rounding"
rat := rat + (rat - 1 >> 8 bitAnd: 16rFF) >> 8 bitAnd: 16rFF. "divide by 255"
((num/255) rounded - rat) abs max: max].
Fix alphaBlendUnscaled; some bits were leaking in the neighbour color.
Use the FastCPrimitiveFlag on primitivePixelValueAt for a 38% speedup.
Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-eem.3171.mcz
==================== Summary ====================
Name: VMMaker.oscog-eem.3171
Author: eem
Time: 24 February 2022, 10:56:30.093719 am
UUID: b926bcd4-a4a9-4d38-8267-4eac3fec60d9
Ancestors: VMMaker.oscog-nice.3170
BitBltPlugin: use the FastCPrimitiveFlag on primitivePixelValueAt
=============== Diff against VMMaker.oscog-nice.3170 ===============
Item was changed:
----- Method: BitBltSimulation>>primitivePixelValueAtX:y: (in category 'primitives') -----
primitivePixelValueAtX: xVal y: yVal
"returns the single pixel at x@y.
It does not handle LSB bitmaps right now.
If x or y are < 0, return 0 to indicate transparent (cf BitBlt>bitPeekerFromForm: usage).
Likewise if x>width or y>depth.
Fail if the rcvr doesn't seem to be a Form, or x|y seem wrong"
+ <primitiveMetadata: #FastCPrimitiveFlag>
| rcvr bitmap depth ppW stride bitsSize word mask shift pixel |
rcvr := self primitive: 'primitivePixelValueAt' parameters: #(SmallInteger SmallInteger) receiver: #Oop.
"possible quick exit if x or y is -ve"
(xVal < 0 or: [ yVal < 0 ] ) ifTrue:[^interpreterProxy integerObjectOf: 0].
"check that rcvr is plausibly a Form or subclass"
rcvr := interpreterProxy stackValue: interpreterProxy methodArgumentCount.
((interpreterProxy isPointers: rcvr) and: [(interpreterProxy slotSizeOf: rcvr) >= 4])
ifFalse: [^interpreterProxy primitiveFail].
"get the bits oop and width/height/depth"
bitmap := interpreterProxy fetchPointer: FormBitsIndex ofObject: rcvr.
(interpreterProxy isWordsOrBytes: bitmap) ifFalse: [^interpreterProxy primitiveFail].
width := interpreterProxy fetchInteger: FormWidthIndex ofObject: rcvr.
height := interpreterProxy fetchInteger: FormHeightIndex ofObject: rcvr.
depth := interpreterProxy fetchInteger: FormDepthIndex ofObject: rcvr.
"if width/height/depth are not integer, fail"
interpreterProxy failed ifTrue:[^nil].
"possible quick exit if x or y is >= extent of form. This also catches cases where the width/height are < 0"
(xVal >= width or: [ yVal >= height ] ) ifTrue:[^interpreterProxy integerObjectOf: 0].
"we don't handle LSB Forms yet"
depth < 0 ifTrue:[^interpreterProxy primitiveFail].
"OK so now we know we have a plausible Form, the width/height/depth/x/y are all reasonable and it's time to plunder the bitmap"
ppW := 32//depth. "pixels in each word"
stride := (width + (ppW -1)) // ppW. "how many words per row of pixels"
bitsSize := interpreterProxy byteSizeOf: bitmap.
bitsSize >= (stride * height * 4 "bytes per word")
ifFalse: [^interpreterProxy primitiveFail].
word := interpreterProxy fetchLong32:(yVal * stride) + (xVal//ppW) ofObject: bitmap. "load the word that contains our target"
mask := 16rFFFFFFFF >> (32 - depth). "make a mask to isolate the pixel within that word"
shift := 32 - (((xVal bitAnd: ppW-1) + 1) * depth). "this is the tricky MSB part - we mask the xVal to find how far into the word we need, then add 1 for the pixel we're looking for, then * depth to get the bit shift"
pixel := (word >> shift) bitAnd: mask. "shift, mask and dim the lights"
^ pixel asPositiveIntegerObj "pop the incoming and push our answer"
!