为什么Java函数比JSNI函数慢得多?

时间:2014-04-19 22:18:46

标签: java javascript html gwt jsni

我比较了在画布图像上进行缩减的两个函数的性能。事实证明,Java函数比JSNI函数慢得多。这很奇怪,因为我假设GWT编译器优化了它至少与JSNI代码一样快的代码。

这是Java函数:

    public static final CanvasElement scaleCanvas(CanvasElement cv, double scale) {

        if (!(scale < 1) || !(scale > 0)) {
            GWT.log("scale must be a positive number <1");
//          throw new Exception("scale must be a positive number <1 ");
        }

        GWT.log("scaleCanvas start");

        double sqScale = scale * scale; // square scale = area of source pixel within target
        int sw = cv.getWidth(); // source image width
        int sh = cv.getHeight(); // source image height
        double tw = Math.ceil(sw * scale); // target image width
        double th = Math.ceil(sh * scale); // target image height
        int sx = 0, sy = 0, sIndex = 0; // source x,y, index within source array
        double tx = 0, ty = 0; 
        int yIndex = 0, tIndex = 0; // target x,y, x,y index within target array
        double tX = 0, tY = 0; // rounded tx, ty
        double w = 0, nw = 0, wx = 0, nwx = 0, wy = 0, nwy = 0; // weight / next weight x / y
        // weight is weight of current source point within target.
        // next weight is weight of current source point within next target's point.
        boolean crossX = false; // does scaled px cross its current px right border ?
        boolean crossY = false; // does scaled px cross its current px bottom border ?
        CanvasPixelArray sBuffer = cv.getContext2d().getImageData(0, 0, sw, sh).getData(); // source buffer 8 bit rgba
        Float32Array tBuffer = TypedArrays.createFloat32Array(4 * sw * sh);

        double sR = 0, sG = 0,  sB = 0; // source's current point r,g,b
        // untested !
        double sA = 0;  //source alpha    


        for (sy = 0; sy < sh; sy++) {
             GWT.log("sy: "+sy+" sh: "+sh);

            ty = sy * scale; // y src position within target
            tY = (long)ty;     // rounded : target pixel's y                            // ?????
            yIndex = (int)Math.floor(4 * tY * tw);  // line index within target array
            crossY = (tY != ( (long)(ty + scale) ));                                                    // ?????
            if (crossY) { // if pixel is crossing botton target pixel
                wy = (tY + 1 - ty); // weight of point within target pixel
                nwy = (ty + scale - tY - 1); // ... within y+1 target pixel
            }
            for (sx = 0; sx < sw; sx++, sIndex += 4) {
                tx = sx * scale; // x src position within target
                tX = (long)tx;    // rounded : target pixel's x                             // ?????
                tIndex = (int)Math.floor(yIndex + tX * 4); // target pixel index within target array                    // ?????
                crossX = (tX != ((int)Math.floor(tx + scale)));
                if (crossX) { // if pixel is crossing target pixel's right
                    wx = (tX + 1 - tx); // weight of point within target pixel
                    nwx = (tx + scale - tX - 1); // ... within x+1 target pixel
                }
                sR = sBuffer.get(sIndex);   // retrieving r,g,b for curr src px.
                sG = sBuffer.get(sIndex + 1);
                sB = sBuffer.get(sIndex + 2);
                sA = sBuffer.get(sIndex + 3);

                if (!crossX && !crossY) { // pixel does not cross
                    // just add components weighted by squared scale.

                    tBuffer.set(tIndex    , (float)(tBuffer.get(tIndex)     + sR * sqScale));
                    tBuffer.set(tIndex + 1, (float)(tBuffer.get(tIndex + 1) + sG * sqScale));
                    tBuffer.set(tIndex + 2, (float)(tBuffer.get(tIndex + 2) + sB * sqScale));
                    tBuffer.set(tIndex + 3, (float)(tBuffer.get(tIndex + 3) + sA * sqScale));
                } else if (crossX && !crossY) { // cross on X only
                    w = wx * scale;
                    // add weighted component for current px
                    tBuffer.set(tIndex    , (float)(tBuffer.get(tIndex)     + sR * w));
                    tBuffer.set(tIndex + 1, (float)(tBuffer.get(tIndex + 1) + sG * w));
                    tBuffer.set(tIndex + 2, (float)(tBuffer.get(tIndex + 2) + sB * w));
                    tBuffer.set(tIndex + 3, (float)(tBuffer.get(tIndex + 3) + sA * w));

                    // add weighted component for next (tX+1) px                
                    nw = nwx * scale;
                    tBuffer.set(tIndex + 4, (float)(tBuffer.get(tIndex + 4) + sR * nw));        // not 3 
                    tBuffer.set(tIndex + 5, (float)(tBuffer.get(tIndex + 5) + sG * nw));        // not 4
                    tBuffer.set(tIndex + 6, (float)(tBuffer.get(tIndex + 6) + sB * nw));        // not 5
                    tBuffer.set(tIndex + 7, (float)(tBuffer.get(tIndex + 7) + sA * nw));        // not 6
                } else if (crossY && !crossX) { // cross on Y only
                    w = wy * scale;
                    // add weighted component for current px
                    tBuffer.set(tIndex    , (float)(tBuffer.get(tIndex)     + sR * w));
                    tBuffer.set(tIndex + 1, (float)(tBuffer.get(tIndex + 1) + sG * w));
                    tBuffer.set(tIndex + 2, (float)(tBuffer.get(tIndex + 2) + sB * w));
                    tBuffer.set(tIndex + 3, (float)(tBuffer.get(tIndex + 3) + sA * w));

                    // add weighted component for next (tY+1) px                
                    nw = nwy * scale;
                    tBuffer.set((int)Math.floor(tIndex + 4 * tw)    , (float)(tBuffer.get((int)Math.floor(tIndex + 4 * tw))     + sR * nw));    // *4, not 3
                    tBuffer.set((int)Math.floor(tIndex + 4 * tw + 1), (float)(tBuffer.get((int)Math.floor(tIndex + 4 * tw + 1)) + sG * nw));    // *4, not 3
                    tBuffer.set((int)Math.floor(tIndex + 4 * tw + 2), (float)(tBuffer.get((int)Math.floor(tIndex + 4 * tw + 2)) + sB * nw));    // *4, not 3
                    tBuffer.set((int)Math.floor(tIndex + 4 * tw + 3), (float)(tBuffer.get((int)Math.floor(tIndex + 4 * tw + 3)) + sA * nw));    // *4, not 3
                } else { // crosses both x and y : four target points involved
                    // add weighted component for current px
                    w = wx * wy;
                    tBuffer.set(tIndex    , (float)(tBuffer.get(tIndex) + sR * w));
                    tBuffer.set(tIndex + 1, (float)(tBuffer.get(tIndex + 1) + sG * w));
                    tBuffer.set(tIndex + 2, (float)(tBuffer.get(tIndex + 2) + sB * w));
                    tBuffer.set(tIndex + 3, (float)(tBuffer.get(tIndex + 3) + sA * w));
                    // for tX + 1; tY px
                    nw = nwx * wy;
                    tBuffer.set(tIndex + 4, (float)(tBuffer.get(tIndex + 4) + sR * nw));    // same for x
                    tBuffer.set(tIndex + 5, (float)(tBuffer.get(tIndex + 5) + sG * nw));
                    tBuffer.set(tIndex + 6, (float)(tBuffer.get(tIndex + 6) + sB * nw));
                    tBuffer.set(tIndex + 7, (float)(tBuffer.get(tIndex + 7) + sA * nw));
                    // for tX ; tY + 1 px
                    nw = wx * nwy;
                    tBuffer.set((int)Math.floor(tIndex + 4 * tw)    , (float)(tBuffer.get((int)Math.floor(tIndex + 4 * tw))     + sR * nw));    // same for mul
                    tBuffer.set((int)Math.floor(tIndex + 4 * tw + 1), (float)(tBuffer.get((int)Math.floor(tIndex + 4 * tw + 1)) + sG * nw));
                    tBuffer.set((int)Math.floor(tIndex + 4 * tw + 2), (float)(tBuffer.get((int)Math.floor(tIndex + 4 * tw + 2)) + sB * nw));
                    tBuffer.set((int)Math.floor(tIndex + 4 * tw + 3), (float)(tBuffer.get((int)Math.floor(tIndex + 4 * tw + 3)) + sA * nw));
                    // for tX + 1 ; tY +1 px
                    nw = nwx * nwy;
                    tBuffer.set((int)Math.floor(tIndex + 4 * tw + 4), (float)(tBuffer.get((int)Math.floor(tIndex + 4 * tw + 4)) + sR * nw)); // same for both x and y
                    tBuffer.set((int)Math.floor(tIndex + 4 * tw + 5), (float)(tBuffer.get((int)Math.floor(tIndex + 4 * tw + 5)) + sG * nw));
                    tBuffer.set((int)Math.floor(tIndex + 4 * tw + 6), (float)(tBuffer.get((int)Math.floor(tIndex + 4 * tw + 6)) + sB * nw));
                    tBuffer.set((int)Math.floor(tIndex + 4 * tw + 7), (float)(tBuffer.get((int)Math.floor(tIndex + 4 * tw + 7)) + sA * nw));
                }
            } // end for sx 
        } // end for sy


        // create result canvas
        Canvas resCV = Canvas.createIfSupported();
        resCV.getCanvasElement().setWidth((int)Math.floor(tw));
        resCV.getCanvasElement().setHeight((int)Math.floor(th));
        Context2d resCtx = resCV.getContext2d();
        ImageData imgRes = resCtx.getImageData(0, 0, tw, th);
        CanvasPixelArray tByteBuffer = imgRes.getData();
        // convert float32 array into a UInt8Clamped Array
        int pxIndex = 0; 
        for (sIndex = 0, tIndex = 0; pxIndex < tw * th; sIndex += 4, tIndex += 4, pxIndex++) {
            tByteBuffer.set(tIndex, (int)Math.ceil(tBuffer.get(sIndex)));
            tByteBuffer.set(tIndex + 1, (int)Math.ceil(tBuffer.get(sIndex + 1)));
            tByteBuffer.set(tIndex + 2, (int)Math.ceil(tBuffer.get(sIndex + 2)));
            tByteBuffer.set(tIndex + 3, (int)Math.ceil(tBuffer.get(sIndex + 3)));
        }
        // writing result to canvas.
        resCtx.putImageData(imgRes, 0, 0);

        return resCV.getCanvasElement();

    }

这是等效的JSNI函数:

public static final native CanvasElement resizeCanvas(CanvasElement cv, double scale) /*-{
        if (!(scale < 1) || !(scale > 0)) throw ('scale must be a positive number <1 ');
        var sqScale = scale * scale; // square scale = area of source pixel within target
        var sw = cv.width; // source image width
        var sh = cv.height; // source image height
        var tw = Math.ceil(sw * scale); // target image width
        var th = Math.ceil(sh * scale); // target image height
        var sx = 0, sy = 0, sIndex = 0; // source x,y, index within source array
        var tx = 0, ty = 0, yIndex = 0, tIndex = 0; // target x,y, x,y index within target array
        var tX = 0, tY = 0; // rounded tx, ty
        var w = 0, nw = 0, wx = 0, nwx = 0, wy = 0, nwy = 0; // weight / next weight x / y
        // weight is weight of current source point within target.
        // next weight is weight of current source point within next target's point.
        var crossX = false; // does scaled px cross its current px right border ?
        var crossY = false; // does scaled px cross its current px bottom border ?
        var sBuffer = cv.getContext('2d').getImageData(0, 0, sw, sh).data; // source buffer 8 bit rgba
        var tBuffer = new Float32Array(4 * sw * sh); // target buffer Float32 rgb
        var sR = 0, sG = 0,  sB = 0; // source's current point r,g,b
        // untested !
        var sA = 0;  //source alpha    

        for (sy = 0; sy < sh; sy++) {
            ty = sy * scale; // y src position within target
            tY = 0 | ty;     // rounded : target pixel's y
            yIndex = 4 * tY * tw;  // line index within target array
            crossY = (tY != (0 | ty + scale)); 
            if (crossY) { // if pixel is crossing botton target pixel
                wy = (tY + 1 - ty); // weight of point within target pixel
                nwy = (ty + scale - tY - 1); // ... within y+1 target pixel
            }
            for (sx = 0; sx < sw; sx++, sIndex += 4) {
                tx = sx * scale; // x src position within target
                tX = 0 |  tx;    // rounded : target pixel's x
                tIndex = yIndex + tX * 4; // target pixel index within target array
                crossX = (tX != (0 | tx + scale));
                if (crossX) { // if pixel is crossing target pixel's right
                    wx = (tX + 1 - tx); // weight of point within target pixel
                    nwx = (tx + scale - tX - 1); // ... within x+1 target pixel
                }
                sR = sBuffer[sIndex    ];   // retrieving r,g,b for curr src px.
                sG = sBuffer[sIndex + 1];
                sB = sBuffer[sIndex + 2];
                sA = sBuffer[sIndex + 3];

                if (!crossX && !crossY) { // pixel does not cross
                    // just add components weighted by squared scale.
                    tBuffer[tIndex    ] += sR * sqScale;
                    tBuffer[tIndex + 1] += sG * sqScale;
                    tBuffer[tIndex + 2] += sB * sqScale;
                    tBuffer[tIndex + 3] += sA * sqScale;
                } else if (crossX && !crossY) { // cross on X only
                    w = wx * scale;
                    // add weighted component for current px
                    tBuffer[tIndex    ] += sR * w;
                    tBuffer[tIndex + 1] += sG * w;
                    tBuffer[tIndex + 2] += sB * w;
                    tBuffer[tIndex + 3] += sA * w;
                    // add weighted component for next (tX+1) px                
                    nw = nwx * scale;
                    tBuffer[tIndex + 4] += sR * nw; // not 3
                    tBuffer[tIndex + 5] += sG * nw; // not 4
                    tBuffer[tIndex + 6] += sB * nw; // not 5
                    tBuffer[tIndex + 7] += sA * nw; // not 6
                } else if (crossY && !crossX) { // cross on Y only
                    w = wy * scale;
                    // add weighted component for current px
                    tBuffer[tIndex    ] += sR * w;
                    tBuffer[tIndex + 1] += sG * w;
                    tBuffer[tIndex + 2] += sB * w;
                    tBuffer[tIndex + 3] += sA * w;
                    // add weighted component for next (tY+1) px                
                    nw = nwy * scale;
                    tBuffer[tIndex + 4 * tw    ] += sR * nw; // *4, not 3
                    tBuffer[tIndex + 4 * tw + 1] += sG * nw; // *4, not 3
                    tBuffer[tIndex + 4 * tw + 2] += sB * nw; // *4, not 3
                    tBuffer[tIndex + 4 * tw + 3] += sA * nw; // *4, not 3
                } else { // crosses both x and y : four target points involved
                    // add weighted component for current px
                    w = wx * wy;
                    tBuffer[tIndex    ] += sR * w;
                    tBuffer[tIndex + 1] += sG * w;
                    tBuffer[tIndex + 2] += sB * w;
                    tBuffer[tIndex + 3] += sA * w;
                    // for tX + 1; tY px
                    nw = nwx * wy;
                    tBuffer[tIndex + 4] += sR * nw; // same for x
                    tBuffer[tIndex + 5] += sG * nw;
                    tBuffer[tIndex + 6] += sB * nw;
                    tBuffer[tIndex + 7] += sA * nw;
                    // for tX ; tY + 1 px
                    nw = wx * nwy;
                    tBuffer[tIndex + 4 * tw    ] += sR * nw; // same for mul
                    tBuffer[tIndex + 4 * tw + 1] += sG * nw;
                    tBuffer[tIndex + 4 * tw + 2] += sB * nw;
                    tBuffer[tIndex + 4 * tw + 3] += sA * nw;
                    // for tX + 1 ; tY +1 px
                    nw = nwx * nwy;
                    tBuffer[tIndex + 4 * tw + 4] += sR * nw; // same for both x and y
                    tBuffer[tIndex + 4 * tw + 5] += sG * nw;
                    tBuffer[tIndex + 4 * tw + 6] += sB * nw;
                    tBuffer[tIndex + 4 * tw + 7] += sA * nw;
                }
            } // end for sx 
        } // end for sy

        // create result canvas
        var resCV = document.createElement('canvas');
        resCV.width = tw;
        resCV.height = th;
        var resCtx = resCV.getContext('2d');
        var imgRes = resCtx.getImageData(0, 0, tw, th);
        var tByteBuffer = imgRes.data;
        // convert float32 array into a UInt8Clamped Array
        var pxIndex = 0; //  
        for (sIndex = 0, tIndex = 0; pxIndex < tw * th; sIndex += 4, tIndex += 4, pxIndex++) {
            tByteBuffer[tIndex] = Math.ceil(tBuffer[sIndex]);
            tByteBuffer[tIndex + 1] = Math.ceil(tBuffer[sIndex + 1]);
            tByteBuffer[tIndex + 2] = Math.ceil(tBuffer[sIndex + 2]);
            tByteBuffer[tIndex + 3] = Math.ceil(tBuffer[sIndex + 3]);
        }
        // writing result to canvas.
        resCtx.putImageData(imgRes, 0, 0);
        return resCV;
}-*/;

为什么Java函数比JSNI函数慢得多?

1 个答案:

答案 0 :(得分:0)

你是否已经编译并在&#34; java场景中运行了应用程序的编译版本&#34; ? 因为,如果你没有,只是从Eclipse Run-&gt; Web应用程序运行。 GWT将在运行时转换javascript中的java代码,这比编译版本慢很多。