Skip to content

Commit babd030

Browse files
authored
Merge pull request #20638 from calixteman/avoid_branching
Avoid branching in convertBlackAndWhiteToRGBA
2 parents 2a2806d + a9870ad commit babd030

1 file changed

Lines changed: 36 additions & 29 deletions

File tree

src/shared/image_utils.js

Lines changed: 36 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -41,30 +41,36 @@ function convertBlackAndWhiteToRGBA({
4141
: [black, nonBlackColor];
4242
const widthInSource = width >> 3;
4343
const widthRemainder = width & 7;
44+
const xorMask = zeroMapping ^ oneMapping;
4445
const srcLength = src.length;
4546
dest = new Uint32Array(dest.buffer);
4647
let destPos = 0;
4748

48-
for (let i = 0; i < height; i++) {
49-
for (const max = srcPos + widthInSource; srcPos < max; srcPos++) {
50-
const elem = srcPos < srcLength ? src[srcPos] : 255;
51-
dest[destPos++] = elem & 0b10000000 ? oneMapping : zeroMapping;
52-
dest[destPos++] = elem & 0b1000000 ? oneMapping : zeroMapping;
53-
dest[destPos++] = elem & 0b100000 ? oneMapping : zeroMapping;
54-
dest[destPos++] = elem & 0b10000 ? oneMapping : zeroMapping;
55-
dest[destPos++] = elem & 0b1000 ? oneMapping : zeroMapping;
56-
dest[destPos++] = elem & 0b100 ? oneMapping : zeroMapping;
57-
dest[destPos++] = elem & 0b10 ? oneMapping : zeroMapping;
58-
dest[destPos++] = elem & 0b1 ? oneMapping : zeroMapping;
49+
for (let i = 0; i < height; ++i) {
50+
for (
51+
const max = srcPos + widthInSource;
52+
srcPos < max;
53+
++srcPos, destPos += 8
54+
) {
55+
const elem = src[srcPos];
56+
dest[destPos] = zeroMapping ^ (-((elem >> 7) & 1) & xorMask);
57+
dest[destPos + 1] = zeroMapping ^ (-((elem >> 6) & 1) & xorMask);
58+
dest[destPos + 2] = zeroMapping ^ (-((elem >> 5) & 1) & xorMask);
59+
dest[destPos + 3] = zeroMapping ^ (-((elem >> 4) & 1) & xorMask);
60+
dest[destPos + 4] = zeroMapping ^ (-((elem >> 3) & 1) & xorMask);
61+
dest[destPos + 5] = zeroMapping ^ (-((elem >> 2) & 1) & xorMask);
62+
dest[destPos + 6] = zeroMapping ^ (-((elem >> 1) & 1) & xorMask);
63+
dest[destPos + 7] = zeroMapping ^ (-(elem & 1) & xorMask);
5964
}
6065
if (widthRemainder === 0) {
6166
continue;
6267
}
6368
const elem = srcPos < srcLength ? src[srcPos++] : 255;
64-
for (let j = 0; j < widthRemainder; j++) {
65-
dest[destPos++] = elem & (1 << (7 - j)) ? oneMapping : zeroMapping;
69+
for (let j = 0; j < widthRemainder; ++j, ++destPos) {
70+
dest[destPos] = zeroMapping ^ (-((elem >> (7 - j)) & 1) & xorMask);
6671
}
6772
}
73+
6874
return { srcPos, destPos };
6975
}
7076

@@ -80,40 +86,41 @@ function convertRGBToRGBA({
8086
const len = width * height * 3;
8187
const len32 = len >> 2;
8288
const src32 = new Uint32Array(src.buffer, srcPos, len32);
89+
const alphaMask = FeatureTest.isLittleEndian ? 0xff000000 : 0xff;
8390

8491
if (FeatureTest.isLittleEndian) {
8592
// It's a way faster to do the shuffle manually instead of working
8693
// component by component with some Uint8 arrays.
8794
for (; i < len32 - 2; i += 3, destPos += 4) {
88-
const s1 = src32[i]; // R2B1G1R1
89-
const s2 = src32[i + 1]; // G3R3B2G2
90-
const s3 = src32[i + 2]; // B4G4R4B3
95+
const s1 = src32[i], // R2B1G1R1
96+
s2 = src32[i + 1], // G3R3B2G2
97+
s3 = src32[i + 2]; // B4G4R4B3
9198

92-
dest[destPos] = s1 | 0xff000000;
93-
dest[destPos + 1] = (s1 >>> 24) | (s2 << 8) | 0xff000000;
94-
dest[destPos + 2] = (s2 >>> 16) | (s3 << 16) | 0xff000000;
95-
dest[destPos + 3] = (s3 >>> 8) | 0xff000000;
99+
dest[destPos] = s1 | alphaMask;
100+
dest[destPos + 1] = (s1 >>> 24) | (s2 << 8) | alphaMask;
101+
dest[destPos + 2] = (s2 >>> 16) | (s3 << 16) | alphaMask;
102+
dest[destPos + 3] = (s3 >>> 8) | alphaMask;
96103
}
97104

98105
for (let j = i * 4, jj = srcPos + len; j < jj; j += 3) {
99106
dest[destPos++] =
100-
src[j] | (src[j + 1] << 8) | (src[j + 2] << 16) | 0xff000000;
107+
src[j] | (src[j + 1] << 8) | (src[j + 2] << 16) | alphaMask;
101108
}
102109
} else {
103110
for (; i < len32 - 2; i += 3, destPos += 4) {
104-
const s1 = src32[i]; // R1G1B1R2
105-
const s2 = src32[i + 1]; // G2B2R3G3
106-
const s3 = src32[i + 2]; // B3R4G4B4
111+
const s1 = src32[i], // R1G1B1R2
112+
s2 = src32[i + 1], // G2B2R3G3
113+
s3 = src32[i + 2]; // B3R4G4B4
107114

108-
dest[destPos] = s1 | 0xff;
109-
dest[destPos + 1] = (s1 << 24) | (s2 >>> 8) | 0xff;
110-
dest[destPos + 2] = (s2 << 16) | (s3 >>> 16) | 0xff;
111-
dest[destPos + 3] = (s3 << 8) | 0xff;
115+
dest[destPos] = s1 | alphaMask;
116+
dest[destPos + 1] = (s1 << 24) | (s2 >>> 8) | alphaMask;
117+
dest[destPos + 2] = (s2 << 16) | (s3 >>> 16) | alphaMask;
118+
dest[destPos + 3] = (s3 << 8) | alphaMask;
112119
}
113120

114121
for (let j = i * 4, jj = srcPos + len; j < jj; j += 3) {
115122
dest[destPos++] =
116-
(src[j] << 24) | (src[j + 1] << 16) | (src[j + 2] << 8) | 0xff;
123+
(src[j] << 24) | (src[j + 1] << 16) | (src[j + 2] << 8) | alphaMask;
117124
}
118125
}
119126

0 commit comments

Comments
 (0)