Improve performance of applyMaskImageData

- write some uint32 instead of uint8 to avoid the check before clamping;
- unroll the loop to write data in the buffer
- but keep a loop for the last element of a line: it likely doesn't hurt
  that much since it's executed only for one time for each line;
- I tested on a macbook with an Apple chip, and on Firefox nightly the new
  code is almost 3.5x faster than before (~1.8x with Chrome).
This commit is contained in:
Calixte Denizet 2022-04-09 20:18:29 +02:00
parent 08e1abe68e
commit 687c9a8710

View File

@ -13,30 +13,42 @@
* limitations under the License. * limitations under the License.
*/ */
import { FeatureTest } from "./util.js";
function applyMaskImageData({ function applyMaskImageData({
src, src,
srcPos = 0, srcPos = 0,
dest, dest,
destPos = 3, destPos = 0,
width, width,
height, height,
inverseDecode = false, inverseDecode = false,
}) { }) {
const srcLength = src.byteLength; const opaque = FeatureTest.isLittleEndian ? 0xff000000 : 0x000000ff;
const zeroMapping = inverseDecode ? 0 : 255; const [zeroMapping, oneMapping] = !inverseDecode ? [opaque, 0] : [0, opaque];
const oneMapping = inverseDecode ? 255 : 0; const widthInSource = width >> 3;
const widthRemainder = width & 7;
const srcLength = src.length;
dest = new Uint32Array(dest.buffer);
for (let j = 0; j < height; j++) { for (let i = 0; i < height; i++) {
let elem, for (const max = srcPos + widthInSource; srcPos < max; srcPos++) {
mask = 0; const elem = srcPos < srcLength ? src[srcPos] : 255;
for (let k = 0; k < width; k++) { dest[destPos++] = elem & 0b10000000 ? oneMapping : zeroMapping;
if (mask === 0) { dest[destPos++] = elem & 0b1000000 ? oneMapping : zeroMapping;
elem = srcPos < srcLength ? src[srcPos++] : 255; dest[destPos++] = elem & 0b100000 ? oneMapping : zeroMapping;
mask = 128; dest[destPos++] = elem & 0b10000 ? oneMapping : zeroMapping;
} dest[destPos++] = elem & 0b1000 ? oneMapping : zeroMapping;
dest[destPos] = elem & mask ? oneMapping : zeroMapping; dest[destPos++] = elem & 0b100 ? oneMapping : zeroMapping;
destPos += 4; dest[destPos++] = elem & 0b10 ? oneMapping : zeroMapping;
mask >>= 1; dest[destPos++] = elem & 0b1 ? oneMapping : zeroMapping;
}
if (widthRemainder === 0) {
continue;
}
const elem = srcPos < srcLength ? src[srcPos++] : 255;
for (let j = 0; j < widthRemainder; j++) {
dest[destPos++] = elem & (1 << (7 - j)) ? oneMapping : zeroMapping;
} }
} }