Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9ce07461 authored by Deepanshu Gupta's avatar Deepanshu Gupta
Browse files

Optimize Blend composites.

Removed redundant array allocations to improve performance for various
blending modes.

Change-Id: Iaba1d6ff3ad03eebdc859c599b610cc593370438
parent 882e0875
Loading
Loading
Loading
Loading
+136 −147
Original line number Diff line number Diff line
@@ -197,12 +197,14 @@ public final class BlendComposite implements Composite {

            int[] srcPixel = new int[4];
            int[] dstPixel = new int[4];
            int[] result = new int[4];
            int[] srcPixels = new int[width];
            int[] dstPixels = new int[width];

            for (int y = 0; y < height; y++) {
                src.getDataElements(0, y, width, 1, srcPixels);
                dstIn.getDataElements(0, y, width, 1, dstPixels);
                if (alpha != 0) {
                    src.getDataElements(0, y, width, 1, srcPixels);
                    for (int x = 0; x < width; x++) {
                        // pixels are stored as INT_ARGB
                        // our arrays are [R, G, B, A]
@@ -218,21 +220,31 @@ public final class BlendComposite implements Composite {
                        dstPixel[2] = (pixel      ) & 0xFF;
                        dstPixel[3] = (pixel >> 24) & 0xFF;

                    int[] result = blender.blend(srcPixel, dstPixel);
                        result = blender.blend(srcPixel, dstPixel, result);

                        // mixes the result with the opacity
                    dstPixels[x] = ((int) (dstPixel[3] + (result[3] - dstPixel[3]) * alpha) & 0xFF) << 24 |
                        if (alpha == 1) {
                            dstPixels[x] = (result[3] & 0xFF) << 24 |
                                           (result[0] & 0xFF) << 16 |
                                           (result[1] & 0xFF) <<  8 |
                                           result[2] & 0xFF;
                        } else {
                            dstPixels[x] =
                                    ((int) (dstPixel[3] + (result[3] - dstPixel[3]) * alpha) & 0xFF) << 24 |
                                    ((int) (dstPixel[0] + (result[0] - dstPixel[0]) * alpha) & 0xFF) << 16 |
                                    ((int) (dstPixel[1] + (result[1] - dstPixel[1]) * alpha) & 0xFF) <<  8 |
                                    (int) (dstPixel[2] + (result[2] - dstPixel[2]) * alpha) & 0xFF;
                        }

                    }
            }
                dstOut.setDataElements(0, y, width, 1, dstPixels);
            }
        }
    }

    private static abstract class Blender {
        public abstract int[] blend(int[] src, int[] dst);
        public abstract int[] blend(int[] src, int[] dst, int[] result);

        private static void RGBtoHSL(int r, int g, int b, float[] hsl) {
            float var_R = (r / 255f);
@@ -346,56 +358,50 @@ public final class BlendComposite implements Composite {
                case NORMAL:
                    return new Blender() {
                        @Override
                        public int[] blend(int[] src, int[] dst) {
                            return src;
                        public int[] blend(int[] src, int[] dst, int[] result) {
                            System.arraycopy(src, 0, result, 0, 4);
                            return result;
                        }
                    };
                case ADD:
                    return new Blender() {
                        @Override
                        public int[] blend(int[] src, int[] dst) {
                            return new int[] {
                                Math.min(255, src[0] + dst[0]),
                                Math.min(255, src[1] + dst[1]),
                                Math.min(255, src[2] + dst[2]),
                                Math.min(255, src[3] + dst[3])
                            };
                        public int[] blend(int[] src, int[] dst, int[] result) {
                            for (int i = 0; i < 4; i++) {
                                result[i] = Math.min(255, src[i] + dst[i]);
                            }
                            return result;
                        }
                    };
                case AVERAGE:
                    return new Blender() {
                        @Override
                        public int[] blend(int[] src, int[] dst) {
                            return new int[] {
                                (src[0] + dst[0]) >> 1,
                                (src[1] + dst[1]) >> 1,
                                (src[2] + dst[2]) >> 1,
                                Math.min(255, src[3] + dst[3])
                            };
                        public int[] blend(int[] src, int[] dst, int[] result) {
                            for (int i = 0; i < 3; i++) {
                                result[i] = (src[i] + dst[i]) >> 1;
                            }
                            result[3] = Math.min(255, src[3] + dst[3]);
                            return result;
                        }
                    };
                case BLUE:
                    return new Blender() {
                        @Override
                        public int[] blend(int[] src, int[] dst) {
                            return new int[] {
                                dst[0],
                                src[1],
                                dst[2],
                                Math.min(255, src[3] + dst[3])
                            };
                        public int[] blend(int[] src, int[] dst, int[] result) {
                            System.arraycopy(dst, 0, result, 0, 3);
                            result[3] = Math.min(255, src[3] + dst[3]);
                            return result;
                        }
                    };
                case COLOR:
                    return new Blender() {
                        @Override
                        public int[] blend(int[] src, int[] dst) {
                        public int[] blend(int[] src, int[] dst, int[] result) {
                            float[] srcHSL = new float[3];
                            RGBtoHSL(src[0], src[1], src[2], srcHSL);
                            float[] dstHSL = new float[3];
                            RGBtoHSL(dst[0], dst[1], dst[2], dstHSL);

                            int[] result = new int[4];
                            HSLtoRGB(srcHSL[0], srcHSL[1], dstHSL[2], result);
                            result[3] = Math.min(255, src[3] + dst[3]);

@@ -405,97 +411,88 @@ public final class BlendComposite implements Composite {
                case COLOR_BURN:
                    return new Blender() {
                        @Override
                        public int[] blend(int[] src, int[] dst) {
                            return new int[] {
                                src[0] == 0 ? 0 :
                                    Math.max(0, 255 - (((255 - dst[0]) << 8) / src[0])),
                                src[1] == 0 ? 0 :
                                    Math.max(0, 255 - (((255 - dst[1]) << 8) / src[1])),
                                src[2] == 0 ? 0 :
                                    Math.max(0, 255 - (((255 - dst[2]) << 8) / src[2])),
                                Math.min(255, src[3] + dst[3])
                            };
                        public int[] blend(int[] src, int[] dst, int[] result) {
                            for (int i = 0; i < 3; i++) {
                                result[i] = src[i] == 0 ? 0 :
                                    Math.max(0, 255 - (((255 - dst[i]) << 8) / src[i]));
                            }
                            result[3] = Math.min(255, src[3] + dst[3]);
                            return result;
                        }
                    };
                case COLOR_DODGE:
                    return new Blender() {
                        @Override
                        public int[] blend(int[] src, int[] dst) {
                            return new int[] {
                                src[0] == 255 ? 255 :
                                    Math.min((dst[0] << 8) / (255 - src[0]), 255),
                                src[1] == 255 ? 255 :
                                    Math.min((dst[1] << 8) / (255 - src[1]), 255),
                                src[2] == 255 ? 255 :
                                    Math.min((dst[2] << 8) / (255 - src[2]), 255),
                                Math.min(255, src[3] + dst[3])
                            };
                        public int[] blend(int[] src, int[] dst, int[] result) {
                            for (int i = 0; i < 3; i++) {
                                result[i] = src[i] == 255 ? 255 :
                                    Math.min((dst[i] << 8) / (255 - src[i]), 255);
                            }
                            result[3] = Math.min(255, src[3] + dst[3]);
                            return result;
                        }
                    };
                case DARKEN:
                    return new Blender() {
                        @Override
                        public int[] blend(int[] src, int[] dst) {
                            return new int[] {
                                Math.min(src[0], dst[0]),
                                Math.min(src[1], dst[1]),
                                Math.min(src[2], dst[2]),
                                Math.min(255, src[3] + dst[3])
                            };
                        public int[] blend(int[] src, int[] dst, int[] result) {
                            for (int i = 0; i < 3; i++) {
                                result[i] = Math.min(src[i], dst[i]);
                            }
                            result[3] = Math.min(255, src[3] + dst[3]);
                            return result;
                        }
                    };
                case DIFFERENCE:
                    return new Blender() {
                        @Override
                        public int[] blend(int[] src, int[] dst) {
                            return new int[] {
                                Math.abs(dst[0] - src[0]),
                                Math.abs(dst[1] - src[1]),
                                Math.abs(dst[2] - src[2]),
                                Math.min(255, src[3] + dst[3])
                            };
                        public int[] blend(int[] src, int[] dst, int[] result) {
                            for (int i = 0; i < 3; i++) {
                                result[i] = dst[i] + src[i] - (dst[i] * src[i] >> 7);
                            }
                            result[3] = Math.min(255, src[3] + dst[3]);
                            return result;
                        }
                    };
                case EXCLUSION:
                    return new Blender() {
                        @Override
                        public int[] blend(int[] src, int[] dst) {
                            return new int[] {
                                dst[0] + src[0] - (dst[0] * src[0] >> 7),
                                dst[1] + src[1] - (dst[1] * src[1] >> 7),
                                dst[2] + src[2] - (dst[2] * src[2] >> 7),
                                Math.min(255, src[3] + dst[3])
                            };
                        public int[] blend(int[] src, int[] dst, int[] result) {
                            for (int i = 0; i < 3; i++) {
                                result[i] = dst[i] + src[i] - (dst[i] * src[i] >> 7);
                            }
                            result[3] = Math.min(255, src[3] + dst[3]);
                            return result;
                        }
                    };
                case FREEZE:
                    return new Blender() {
                        @Override
                        public int[] blend(int[] src, int[] dst) {
                            return new int[] {
                                src[0] == 0 ? 0 : Math.max(0, 255 - (255 - dst[0]) * (255 - dst[0]) / src[0]),
                                src[1] == 0 ? 0 : Math.max(0, 255 - (255 - dst[1]) * (255 - dst[1]) / src[1]),
                                src[2] == 0 ? 0 : Math.max(0, 255 - (255 - dst[2]) * (255 - dst[2]) / src[2]),
                                Math.min(255, src[3] + dst[3])
                            };
                        public int[] blend(int[] src, int[] dst, int[] result) {
                            for (int i = 0; i < 3; i++) {
                                result[i] = src[i] == 0 ? 0 :
                                    Math.max(0, 255 - (255 - dst[i]) * (255 - dst[i]) / src[i]);
                            }
                            result[3] = Math.min(255, src[3] + dst[3]);
                            return result;
                        }
                    };
                case GLOW:
                    return new Blender() {
                        @Override
                        public int[] blend(int[] src, int[] dst) {
                            return new int[] {
                                dst[0] == 255 ? 255 : Math.min(255, src[0] * src[0] / (255 - dst[0])),
                                dst[1] == 255 ? 255 : Math.min(255, src[1] * src[1] / (255 - dst[1])),
                                dst[2] == 255 ? 255 : Math.min(255, src[2] * src[2] / (255 - dst[2])),
                                Math.min(255, src[3] + dst[3])
                            };
                        public int[] blend(int[] src, int[] dst, int[] result) {
                            for (int i = 0; i < 3; i++) {
                                result[i] = dst[i] == 255 ? 255 :
                                    Math.min(255, src[i] * src[i] / (255 - dst[i]));
                            }
                            result[3] = Math.min(255, src[3] + dst[3]);
                            return result;
                        }
                    };
                case GREEN:
                    return new Blender() {
                        @Override
                        public int[] blend(int[] src, int[] dst) {
                        public int[] blend(int[] src, int[] dst, int[] result) {
                            return new int[] {
                                dst[0],
                                dst[1],
@@ -507,7 +504,7 @@ public final class BlendComposite implements Composite {
                case HARD_LIGHT:
                    return new Blender() {
                        @Override
                        public int[] blend(int[] src, int[] dst) {
                        public int[] blend(int[] src, int[] dst, int[] result) {
                            return new int[] {
                                src[0] < 128 ? dst[0] * src[0] >> 7 :
                                    255 - ((255 - src[0]) * (255 - dst[0]) >> 7),
@@ -522,7 +519,7 @@ public final class BlendComposite implements Composite {
                case HEAT:
                    return new Blender() {
                        @Override
                        public int[] blend(int[] src, int[] dst) {
                        public int[] blend(int[] src, int[] dst, int[] result) {
                            return new int[] {
                                dst[0] == 0 ? 0 : Math.max(0, 255 - (255 - src[0]) * (255 - src[0]) / dst[0]),
                                dst[1] == 0 ? 0 : Math.max(0, 255 - (255 - src[1]) * (255 - src[1]) / dst[1]),
@@ -534,13 +531,12 @@ public final class BlendComposite implements Composite {
                case HUE:
                    return new Blender() {
                        @Override
                        public int[] blend(int[] src, int[] dst) {
                        public int[] blend(int[] src, int[] dst, int[] result) {
                            float[] srcHSL = new float[3];
                            RGBtoHSL(src[0], src[1], src[2], srcHSL);
                            float[] dstHSL = new float[3];
                            RGBtoHSL(dst[0], dst[1], dst[2], dstHSL);

                            int[] result = new int[4];
                            HSLtoRGB(srcHSL[0], dstHSL[1], dstHSL[2], result);
                            result[3] = Math.min(255, src[3] + dst[3]);

@@ -550,7 +546,7 @@ public final class BlendComposite implements Composite {
                case INVERSE_COLOR_BURN:
                    return new Blender() {
                        @Override
                        public int[] blend(int[] src, int[] dst) {
                        public int[] blend(int[] src, int[] dst, int[] result) {
                            return new int[] {
                                dst[0] == 0 ? 0 :
                                    Math.max(0, 255 - (((255 - src[0]) << 8) / dst[0])),
@@ -565,7 +561,7 @@ public final class BlendComposite implements Composite {
                case INVERSE_COLOR_DODGE:
                    return new Blender() {
                        @Override
                        public int[] blend(int[] src, int[] dst) {
                        public int[] blend(int[] src, int[] dst, int[] result) {
                            return new int[] {
                                dst[0] == 255 ? 255 :
                                    Math.min((src[0] << 8) / (255 - dst[0]), 255),
@@ -580,25 +576,23 @@ public final class BlendComposite implements Composite {
                case LIGHTEN:
                    return new Blender() {
                        @Override
                        public int[] blend(int[] src, int[] dst) {
                            return new int[] {
                                Math.max(src[0], dst[0]),
                                Math.max(src[1], dst[1]),
                                Math.max(src[2], dst[2]),
                                Math.min(255, src[3] + dst[3])
                            };
                        public int[] blend(int[] src, int[] dst, int[] result) {
                            for (int i = 0; i < 3; i++) {
                                result[i] = Math.max(src[i], dst[i]);
                            }
                            result[3] = Math.min(255, src[3] + dst[3]);
                            return result;
                        }
                    };
                case LUMINOSITY:
                    return new Blender() {
                        @Override
                        public int[] blend(int[] src, int[] dst) {
                        public int[] blend(int[] src, int[] dst, int[] result) {
                            float[] srcHSL = new float[3];
                            RGBtoHSL(src[0], src[1], src[2], srcHSL);
                            float[] dstHSL = new float[3];
                            RGBtoHSL(dst[0], dst[1], dst[2], dstHSL);

                            int[] result = new int[4];
                            HSLtoRGB(dstHSL[0], dstHSL[1], srcHSL[2], result);
                            result[3] = Math.min(255, src[3] + dst[3]);

@@ -608,19 +602,18 @@ public final class BlendComposite implements Composite {
                case MULTIPLY:
                    return new Blender() {
                        @Override
                        public int[] blend(int[] src, int[] dst) {
                            return new int[] {
                                (src[0] * dst[0]) >> 8,
                                (src[1] * dst[1]) >> 8,
                                (src[2] * dst[2]) >> 8,
                                Math.min(255, src[3] + dst[3])
                            };
                        public int[] blend(int[] src, int[] dst, int[] result) {
                            for (int i = 0; i < 3; i++) {
                                result[i] = (src[i] * dst[i]) >> 8;
                            }
                            result[3] = Math.min(255, src[3] + dst[3]);
                            return result;
                        }
                    };
                case NEGATION:
                    return new Blender() {
                        @Override
                        public int[] blend(int[] src, int[] dst) {
                        public int[] blend(int[] src, int[] dst, int[] result) {
                            return new int[] {
                                255 - Math.abs(255 - dst[0] - src[0]),
                                255 - Math.abs(255 - dst[1] - src[1]),
@@ -632,22 +625,19 @@ public final class BlendComposite implements Composite {
                case OVERLAY:
                    return new Blender() {
                        @Override
                        public int[] blend(int[] src, int[] dst) {
                            return new int[] {
                                dst[0] < 128 ? dst[0] * src[0] >> 7 :
                                    255 - ((255 - dst[0]) * (255 - src[0]) >> 7),
                                dst[1] < 128 ? dst[1] * src[1] >> 7 :
                                    255 - ((255 - dst[1]) * (255 - src[1]) >> 7),
                                dst[2] < 128 ? dst[2] * src[2] >> 7 :
                                    255 - ((255 - dst[2]) * (255 - src[2]) >> 7),
                                Math.min(255, src[3] + dst[3])
                            };
                        public int[] blend(int[] src, int[] dst, int[] result) {
                            for (int i = 0; i < 3; i++) {
                                result[i] = dst[i] < 128 ? dst[i] * src[i] >> 7 :
                                    255 - ((255 - dst[i]) * (255 - src[i]) >> 7);
                            }
                            result[3] = Math.min(255, src[3] + dst[3]);
                            return result;
                        }
                    };
                case RED:
                    return new Blender() {
                        @Override
                        public int[] blend(int[] src, int[] dst) {
                        public int[] blend(int[] src, int[] dst, int[] result) {
                            return new int[] {
                                src[0],
                                dst[1],
@@ -659,7 +649,7 @@ public final class BlendComposite implements Composite {
                case REFLECT:
                    return new Blender() {
                        @Override
                        public int[] blend(int[] src, int[] dst) {
                        public int[] blend(int[] src, int[] dst, int[] result) {
                            return new int[] {
                                src[0] == 255 ? 255 : Math.min(255, dst[0] * dst[0] / (255 - src[0])),
                                src[1] == 255 ? 255 : Math.min(255, dst[1] * dst[1] / (255 - src[1])),
@@ -671,13 +661,12 @@ public final class BlendComposite implements Composite {
                case SATURATION:
                    return new Blender() {
                        @Override
                        public int[] blend(int[] src, int[] dst) {
                        public int[] blend(int[] src, int[] dst, int[] result) {
                            float[] srcHSL = new float[3];
                            RGBtoHSL(src[0], src[1], src[2], srcHSL);
                            float[] dstHSL = new float[3];
                            RGBtoHSL(dst[0], dst[1], dst[2], dstHSL);

                            int[] result = new int[4];
                            HSLtoRGB(dstHSL[0], srcHSL[1], dstHSL[2], result);
                            result[3] = Math.min(255, src[3] + dst[3]);

@@ -687,7 +676,7 @@ public final class BlendComposite implements Composite {
                case SCREEN:
                    return new Blender() {
                        @Override
                        public int[] blend(int[] src, int[] dst) {
                        public int[] blend(int[] src, int[] dst, int[] result) {
                            return new int[] {
                                255 - ((255 - src[0]) * (255 - dst[0]) >> 8),
                                255 - ((255 - src[1]) * (255 - dst[1]) >> 8),
@@ -699,7 +688,7 @@ public final class BlendComposite implements Composite {
                case SOFT_BURN:
                    return new Blender() {
                        @Override
                        public int[] blend(int[] src, int[] dst) {
                        public int[] blend(int[] src, int[] dst, int[] result) {
                            return new int[] {
                                dst[0] + src[0] < 256 ?
	                                (dst[0] == 255 ? 255 :
@@ -720,7 +709,7 @@ public final class BlendComposite implements Composite {
                case SOFT_DODGE:
                    return new Blender() {
                        @Override
                        public int[] blend(int[] src, int[] dst) {
                        public int[] blend(int[] src, int[] dst, int[] result) {
                            return new int[] {
                                dst[0] + src[0] < 256 ?
                                    (src[0] == 255 ? 255 :
@@ -743,7 +732,7 @@ public final class BlendComposite implements Composite {
                case STAMP:
                    return new Blender() {
                        @Override
                        public int[] blend(int[] src, int[] dst) {
                        public int[] blend(int[] src, int[] dst, int[] result) {
                            return new int[] {
                                Math.max(0, Math.min(255, dst[0] + 2 * src[0] - 256)),
                                Math.max(0, Math.min(255, dst[1] + 2 * src[1] - 256)),
@@ -755,7 +744,7 @@ public final class BlendComposite implements Composite {
                case SUBTRACT:
                    return new Blender() {
                        @Override
                        public int[] blend(int[] src, int[] dst) {
                        public int[] blend(int[] src, int[] dst, int[] result) {
                            return new int[] {
                                Math.max(0, src[0] + dst[0] - 256),
                                Math.max(0, src[1] + dst[1] - 256),