Search code examples
androidrenderscript

Renderscript is slow, is it ok?


I have two implimentations of image saturation filter. One with Java and one with Renderscript. Actually the renderscript is slower on my nexus 4 device, how can it be?

Java implementation:

public final void Saturation(Bitmap canvas, int saturation, boolean accumulate, int imageNumber)
{
    int height = canvas.getHeight();
    int width = canvas.getWidth();
    int[] pixels = new int[height*width];
    int[] resultPixels = new int[height*width];
    canvas.getPixels(pixels, 0, width, 0, 0, width, height);

    if (!accumulate)
    {
        for (int i = 0; i < pixels.length; i ++)
        {
            int red = Color.red(pixels[i]);
            int green = Color.green(pixels[i]);
            int blue = Color.blue(pixels[i]);

            double t = (double)red * 0.11 + (double)green * 0.59 + (double)blue * 0.3;
            red = (int)Math.round(Math.min((double)red + (t - (double)red) * saturation / 100.0, 255));
            green = (int)Math.round(Math.min((double)green + (t - (double)green) * saturation / 100.0, 255));
            blue = (int)Math.round(Math.min((double)blue + (t - (double)blue) * saturation / 100.0, 255));

            resultPixels[i] = Color.argb(Color.alpha(pixels[i]), red, green, blue);
        }
    }

    canvas.setPixels(resultPixels, 0, width, 0, 0, width, height);
}

Renderscript implementation:

Java part:

public static Bitmap saturate(Bitmap bmIn, float saturation, Context context, Resources resources)
{
    Bitmap bmOut = Bitmap.createBitmap(bmIn.getWidth(), bmIn.getHeight(),
            bmIn.getConfig());
    RenderScript rs = RenderScript.create(context);
    Allocation allocIn;
    allocIn = Allocation.createFromBitmap(rs, bmIn,
            Allocation.MipmapControl.MIPMAP_NONE,
            Allocation.USAGE_SCRIPT);
    Allocation allocOut = Allocation.createTyped(rs, allocIn.getType());
    ScriptC_saturation script = new ScriptC_saturation(rs, resources,
            R.raw.saturation);
    script.set_in(allocIn);
    script.set_out(allocOut);
    script.set_script(script);
    script.set_saturation(saturation);
    script.invoke_filter();
    allocOut.copyTo(bmOut);
    return bmOut;
}

Renderscript script:

#pragma version(1)
#pragma rs java_package_name(ca.tutortutor.embossimage)

rs_allocation out;
rs_allocation in;
rs_script script;
float saturation;

void root(const uchar4* v_in, uchar4* v_out, const void* usrData, uint32_t x,
      uint32_t y)
{
    float4 current = rsUnpackColor8888(*v_in);

    float t = current.r * 0.11f + current.g * 0.59f + current.b * 0.3f;
    rsDebug("renderscript t = ", t);
    rsDebug("renderscript red before = ", current.r);
    current.r = fmin(current.r + (t - current.r) * saturation / 100.0f, 1.f);
    current.g = fmin(current.g + (t - current.g) * saturation / 100.0f, 1.f);
    current.b = fmin(current.b + (t - current.b) * saturation / 100.0f, 1.f);
    rsDebug("renderscript red after = ", current.r);

    *v_out = rsPackColorTo8888(current.r, current.g, current.b, current.a);
}

void filter()
{
    rsDebug("RS_VERSION = ", RS_VERSION);
    #if !defined(RS_VERSION) || (RS_VERSION < 14)
        rsForEach(script, in, out, 0);
    #else
        rsForEach(script, in, out);
    #endif
}

I thought that renderscript should be much faster than java because it should use all 4 cores of the cpu and native code and may be even gpu cores on android 4.2.2.


Solution

  • I immediately can see that your Renderscript code is printing to the log using rsDebug(), which is guaranteed to be slow. Try removing your logging code and measure the timing again. Nexus 4 should execute on 4 CPU threads in this case. There is currently no GPU support on Nexus 4.