[Vm-dev] [OpenSmalltalk/opensmalltalk-vm] BitBlt rule blendAlphaScaled may not be correct (Issue #643)

MariusDoe notifications at github.com
Thu Jun 30 19:43:08 UTC 2022


The `BitBlt` blending rule `Form blendAlphaScaled` (`34`) doesn't blend the colors `0x00000000` (source; fully transparent) and `0xFFFFFFFF` (destination; white) correctly. The output is `0xFEFEFEFE` (slightly transparent white), whereas it should be `0xFFFFFFFF` (fully opaque white).

I think the problem lies in [the implementation](https://github.com/OpenSmalltalk/opensmalltalk-vm/blob/a45e38820e50ffe19ac61428df88ebcd724e67e8/src/plugins/BitBltPlugin/BitBltPlugin.c#L557) of `BitBltSimulation>>#alphaBlendScaled:with:`. When calculating the summand containing the `destinationWord`, a right bit shift by `8` is performed to normalize the result after multiplying with `unAlpha` (semantically a division by `256`). However, `unAlpha` is in the range `0x00` - `0xFF` and thus a division by `0xFF = 255` should be used instead. I think that the other bit shifts by `8` in the function are ok, as they are only used to extract or compose certain bytes and not to (semantically) divide a value by `256`.

This problem causes the described behavior, because the following computation is performed in each channel:
```((0xFF * 0xFF) >> 8) + 0x00 = 0xFE01 >> 8 = 0xFE```
A division by `0xFF` produces the expected result:
```((0xFF * 0xFF) / 0xFF) + 0x00 = 0xFE01 / 0xFF = 0xFF```

Code to reproduce:
```
| src dst |
src := (Form extent: 1 @ 1 depth: 1)
    colorAt: 0 @ 0 put: Color black; "transparency is applied with the fillColor:"
    yourself.
dst := (Form extent: 1 @ 1 depth: 32)
    colorAt: 0 @ 0 put: Color white; "16rFFFFFFFF"
    yourself.
dst
    copyBits: (0 @ 0 corner: 1 @ 1)
    from: src
    at: 0 @ 0
    clippingBox: (0 @ 0 corner: 1 @ 1)
    rule: Form blendAlphaScaled
    fillColor: Color transparent. "16r00000000"
(dst pixelValueAt: 0 @ 0) hex "16rFEFEFEFE"
```

Notes:
- I did not thoroughly test the proposed change, just calculated the result for the described case.
- I am no expert in writing high performance code, but a potential improved implementation may not use a division but rather a more optimized combination of `+`, `*` and `>>` to increase performance. A quick search on the internet shows some possible alternatives.
- I read in the contribution guidelines, that the VM is developed in Smalltalk and the C code is only generated from the Smalltalk code. I did not have the time to set up a VM image and just looked into the C code to find the problem. I hope the problem description still helps.
- The described behavior doesn't occur when blending two 32 bit `Form`s. I think this is due to `alphaSourceBlendBits32` being called in this case, which is optimized for edge cases with full or zero transparency and handles those correctly (it doesn't call `alphaBlendScaledwith`).

-- 
Reply to this email directly or view it on GitHub:
https://github.com/OpenSmalltalk/opensmalltalk-vm/issues/643
You are receiving this because you are subscribed to this thread.

Message ID: <OpenSmalltalk/opensmalltalk-vm/issues/643 at github.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/vm-dev/attachments/20220630/a4e0c052/attachment.html>


More information about the Vm-dev mailing list