3
votes

My app uses a proprietary implementation of Canny edge detection based on RenderScript. I tested this on numerous devices with various APIs and it worked very reliably. Now I got the new Samsung S7 working on API23. Here (and only here) I encountered a rather ugly problem. Some of the edge pictures are studded with thousands of artifacts that stem from the Magnitude gradient calculation kernel and are NOT based on actual image information. After trying with all kind of TargetAPIs, taking renderscript.support.mode on and off, etc. I finally found that the problem only arises, when the RenderScript (and Script) instances are used for the second or more times. It does not arise when using them for the first time.

For efficiency reasons I created the RenderScript and Script instances only once in the onCreate method of MainActivity and used it repeatedly thereafter. Of course I don't like to change that.

Does anyone have a solution of this problem? Thanks.

UPDATE: Crazy things are going on here. It seems that freshly created Allocations are NOT empty from the outset! When running:

    Type.Builder typeUCHAR1 = new Type.Builder(rs, Element.U8(rs));
    typeUCHAR1.setX(width).setY(height);
    Allocation alloc = Allocation.createTyped(rs, typeUCHAR1.create());

    byte se[] = new byte[width*height];
    alloc.copyTo(se);

    for (int i=0;i<width*height;i++){
        if (se[i]!=0){
            Log.e("content: ", String.valueOf(se[i]));
        }
    }

... the byte Array se is full of funny numbers.... HELP! Any idea, what is going on here?

UPDATE2: I stumbled over my own ignorance here - and really don't deserve a point for this masterpiece.... However, to my defense I must say that the problem was slightly more subtle that it appears here. The context was, that I needed to assign a global allocation (Byte/U8) which initially should be empty (i.e. zero) and then, within the kernel getting partially set to 1 (only where the edges are) via rsSetElementAt_uchar(). Since this worked for many months, I was not aware anymore of the fact, that I didn't explicitely assign the zeros in this allocation.... This only had consequences in API 23, so maybe this can help others not to fall into this trap.... So, note: other than numerical Arrays that are filled with 0 (as by Java default), Allocations cannot assumed to be full of zeros at initiation. Thanks, Sakridge.

1
Are you using intrinsics or all custom Scripts? Do you have global data in your custom Scripts? Are you reusing Allocations between these runs (as opposed to just reusing the RenderScript and Script objects)? You might also want to try running under just CPU mode (in case this is GPU-related). Try "adb shell setprop debug.rs.default-CPU-driver 1", and see if it is any different. - Stephen Hines
I am using the ScriptIntrinsicBlur and YUVtoRGB (for the old camera API). I also see the problem only with the computationally most intense kernel, which is a Sobel 5x5 convolution (although I assume that the ScriptIntrinsicBlur does even more work). And yes, I am also reuising allocations in the sense that I do not copy outAllocations into arrays when I use them again in the next kernel. Indeed that problem disappears when I run it on CPU only. Is there a way to make this permanent on all devices? - Settembrini
From your comment here stackoverflow.com/a/25253181/5148048 I conclude, that there is no other solution than recreating the rs instance each time I use my kernels, thus taking "benefit" from the fact that the first rs-run is performed on CPU only (as it also appears from other posts). - Settembrini
Unfortunately the recreation of rs instances does not help either, as it does not reliably run on CPU only. - Settembrini

1 Answers

2
votes

Allocation data for primitive types (non-struct/object) is not initialized by default when an Allocation is created unless passed a bitmap using the createFromBitmap api. If you are expecting this then possibly you have a bug in your app which is not exposed when the driver initializes to 0s. It would help if you can post example code which reproduces the problem.

Initialize your allocations by copying from a bitmap or Java array.