ImageFilterRS.java revision 180277924bebf6b600ee5ce5adf9ff807a038570
1a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard/*
2a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * Copyright (C) 2012 The Android Open Source Project
3a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard *
4a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * Licensed under the Apache License, Version 2.0 (the "License");
5a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * you may not use this file except in compliance with the License.
6a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * You may obtain a copy of the License at
7a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard *
8a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard *      http://www.apache.org/licenses/LICENSE-2.0
9a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard *
10a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * Unless required by applicable law or agreed to in writing, software
11a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * distributed under the License is distributed on an "AS IS" BASIS,
12a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * See the License for the specific language governing permissions and
14a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * limitations under the License.
15a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard */
16a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard
175448bf8095483574649afcc2add7f153670c7450nicolasroardpackage com.android.gallery3d.filtershow.filters;
185448bf8095483574649afcc2add7f153670c7450nicolasroard
195448bf8095483574649afcc2add7f153670c7450nicolasroardimport android.app.Activity;
205448bf8095483574649afcc2add7f153670c7450nicolasroardimport android.graphics.Bitmap;
2196df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroardimport android.graphics.BitmapFactory;
22a64051696e46fb5d5e1c76e53ac95a4feba18585Tim Murrayimport android.support.v8.renderscript.*;
235448bf8095483574649afcc2add7f153670c7450nicolasroardimport android.util.Log;
24575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunkimport android.content.res.Resources;
25a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murrayimport com.android.gallery3d.R;
26fc8a6a38c699c0d75fa29664d9aaa369d361c335nicolasroardimport com.android.gallery3d.filtershow.cache.CachingPipeline;
275448bf8095483574649afcc2add7f153670c7450nicolasroard
284e6c07b71b269ee3fe7f6fa455bc540238df9dedJohn Hofordpublic abstract class ImageFilterRS extends ImageFilter {
29575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk    private static final String LOGTAG = "ImageFilterRS";
30180277924bebf6b600ee5ce5adf9ff807a038570nicolasroard    private boolean DEBUG = false;
315448bf8095483574649afcc2add7f153670c7450nicolasroard
32575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk    private static volatile RenderScript sRS = null;
33575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk    private static volatile Resources sResources = null;
34ea5355e6aa782bb61fbf079f4811873a67a83808Ruben Brunk    private volatile boolean mResourcesLoaded = false;
3557eedfd99676913f575b1f76e3a874026d1ddf7cnicolasroard
36575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk    // This must be used inside block synchronized on ImageFilterRS class object
37ea5355e6aa782bb61fbf079f4811873a67a83808Ruben Brunk    protected abstract void createFilter(android.content.res.Resources res,
387706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard            float scaleFactor, int quality);
395448bf8095483574649afcc2add7f153670c7450nicolasroard
40575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk    // This must be used inside block synchronized on ImageFilterRS class object
41ea5355e6aa782bb61fbf079f4811873a67a83808Ruben Brunk    protected abstract void runFilter();
425448bf8095483574649afcc2add7f153670c7450nicolasroard
43575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk    // This must be used inside block synchronized on ImageFilterRS class object
44ea5355e6aa782bb61fbf079f4811873a67a83808Ruben Brunk    protected void update(Bitmap bitmap) {
45fc8a6a38c699c0d75fa29664d9aaa369d361c335nicolasroard        getOutPixelsAllocation().copyTo(bitmap);
46fc8a6a38c699c0d75fa29664d9aaa369d361c335nicolasroard    }
47fc8a6a38c699c0d75fa29664d9aaa369d361c335nicolasroard
48fc8a6a38c699c0d75fa29664d9aaa369d361c335nicolasroard    protected Allocation getInPixelsAllocation() {
49fc8a6a38c699c0d75fa29664d9aaa369d361c335nicolasroard        CachingPipeline pipeline = getEnvironment().getCachingPipeline();
50fc8a6a38c699c0d75fa29664d9aaa369d361c335nicolasroard        return pipeline.getInPixelsAllocation();
51fc8a6a38c699c0d75fa29664d9aaa369d361c335nicolasroard    }
52fc8a6a38c699c0d75fa29664d9aaa369d361c335nicolasroard
53fc8a6a38c699c0d75fa29664d9aaa369d361c335nicolasroard    protected Allocation getOutPixelsAllocation() {
54fc8a6a38c699c0d75fa29664d9aaa369d361c335nicolasroard        CachingPipeline pipeline = getEnvironment().getCachingPipeline();
55fc8a6a38c699c0d75fa29664d9aaa369d361c335nicolasroard        return pipeline.getOutPixelsAllocation();
565448bf8095483574649afcc2add7f153670c7450nicolasroard    }
575448bf8095483574649afcc2add7f153670c7450nicolasroard
5881eb9976f967d9b3faa1749a8ab29d1743cf347dnicolasroard    @Override
5999baf61387ab1ef15bb9db5fa3b2b55591e87059John Hoford    public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) {
60575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk        if (bitmap == null || bitmap.getWidth() == 0 || bitmap.getHeight() == 0) {
6181eb9976f967d9b3faa1749a8ab29d1743cf347dnicolasroard            return bitmap;
625448bf8095483574649afcc2add7f153670c7450nicolasroard        }
635448bf8095483574649afcc2add7f153670c7450nicolasroard        try {
64575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk            synchronized(ImageFilterRS.class) {
65575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk                if (sRS == null)  {
66ea5355e6aa782bb61fbf079f4811873a67a83808Ruben Brunk                    Log.w(LOGTAG, "Cannot apply before calling createRenderScriptContext");
67575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk                    return bitmap;
68575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk                }
69fc8a6a38c699c0d75fa29664d9aaa369d361c335nicolasroard                CachingPipeline pipeline = getEnvironment().getCachingPipeline();
70180277924bebf6b600ee5ce5adf9ff807a038570nicolasroard                if (DEBUG) {
71180277924bebf6b600ee5ce5adf9ff807a038570nicolasroard                    Log.v(LOGTAG, "apply filter " + getName() + " in pipeline " + pipeline.getName());
72180277924bebf6b600ee5ce5adf9ff807a038570nicolasroard                }
73fc8a6a38c699c0d75fa29664d9aaa369d361c335nicolasroard                boolean needsUpdate = pipeline.prepareRenderscriptAllocations(bitmap);
74fc8a6a38c699c0d75fa29664d9aaa369d361c335nicolasroard                if (needsUpdate || !isResourcesLoaded()) {
75fc8a6a38c699c0d75fa29664d9aaa369d361c335nicolasroard                    // the allocations changed size
76fc8a6a38c699c0d75fa29664d9aaa369d361c335nicolasroard                    freeResources();
77fc8a6a38c699c0d75fa29664d9aaa369d361c335nicolasroard                    createFilter(sResources, scaleFactor, quality);
78fc8a6a38c699c0d75fa29664d9aaa369d361c335nicolasroard                    setResourcesLoaded(true);
79fc8a6a38c699c0d75fa29664d9aaa369d361c335nicolasroard                }
80575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk                runFilter();
81575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk                update(bitmap);
82180277924bebf6b600ee5ce5adf9ff807a038570nicolasroard                if (DEBUG) {
83180277924bebf6b600ee5ce5adf9ff807a038570nicolasroard                    Log.v(LOGTAG, "DONE apply filter " + getName() + " in pipeline " + pipeline.getName());
84180277924bebf6b600ee5ce5adf9ff807a038570nicolasroard                }
85575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk            }
865448bf8095483574649afcc2add7f153670c7450nicolasroard        } catch (android.renderscript.RSIllegalArgumentException e) {
875448bf8095483574649afcc2add7f153670c7450nicolasroard            Log.e(LOGTAG, "Illegal argument? " + e);
885448bf8095483574649afcc2add7f153670c7450nicolasroard        } catch (android.renderscript.RSRuntimeException e) {
895448bf8095483574649afcc2add7f153670c7450nicolasroard            Log.e(LOGTAG, "RS runtime exception ? " + e);
90b17b1b0758799914fbad5f4a3afae71ce58891fcRuben Brunk        } catch (java.lang.OutOfMemoryError e) {
91b17b1b0758799914fbad5f4a3afae71ce58891fcRuben Brunk            // Many of the renderscript filters allocated large (>16Mb resources) in order to apply.
92b17b1b0758799914fbad5f4a3afae71ce58891fcRuben Brunk            System.gc();
93b17b1b0758799914fbad5f4a3afae71ce58891fcRuben Brunk            displayLowMemoryToast();
94b17b1b0758799914fbad5f4a3afae71ce58891fcRuben Brunk            Log.e(LOGTAG, "not enough memory for filter " + getName(), e);
955448bf8095483574649afcc2add7f153670c7450nicolasroard        }
9681eb9976f967d9b3faa1749a8ab29d1743cf347dnicolasroard        return bitmap;
975448bf8095483574649afcc2add7f153670c7450nicolasroard    }
985448bf8095483574649afcc2add7f153670c7450nicolasroard
99575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk    public static synchronized RenderScript getRenderScriptContext() {
100575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk        return sRS;
1015448bf8095483574649afcc2add7f153670c7450nicolasroard    }
1025448bf8095483574649afcc2add7f153670c7450nicolasroard
103d7c61b63a1ea0d86cd10861834fd2783c54a4632Ruben Brunk    public static synchronized void createRenderscriptContext(Activity context) {
104575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk        if( sRS != null) {
105575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk            Log.w(LOGTAG, "A prior RS context exists when calling setRenderScriptContext");
106575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk            destroyRenderScriptContext();
1077921e124d57759d6f0887a42ddc360d923e60cddTim Murray        }
108575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk        sRS = RenderScript.create(context);
109575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk        sResources = context.getResources();
110575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk    }
111575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk
112575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk    public static synchronized void destroyRenderScriptContext() {
113575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk        sRS.destroy();
114575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk        sRS = null;
115575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk        sResources = null;
1165448bf8095483574649afcc2add7f153670c7450nicolasroard    }
1175448bf8095483574649afcc2add7f153670c7450nicolasroard
118575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk    private static synchronized Allocation convertBitmap(Bitmap bitmap) {
119575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk        return Allocation.createFromBitmap(sRS, bitmap,
12096df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard                Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
12196df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard    }
12296df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard
123575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk    private static synchronized Allocation convertRGBAtoA(Bitmap bitmap) {
1247428a933c89e2d49036a1854143d5c28078fec75Tim Murray        Type.Builder tb_a8 = new Type.Builder(sRS, Element.A_8(sRS));
125575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk        ScriptC_grey greyConvert = new ScriptC_grey(sRS,
126575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk                sRS.getApplicationContext().getResources(), R.raw.grey);
127a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray
12896df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        Allocation bitmapTemp = convertBitmap(bitmap);
1297428a933c89e2d49036a1854143d5c28078fec75Tim Murray        if (bitmapTemp.getType().getElement().isCompatible(Element.A_8(sRS))) {
130a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray            return bitmapTemp;
131a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray        }
132a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray
133a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray        tb_a8.setX(bitmapTemp.getType().getX());
134a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray        tb_a8.setY(bitmapTemp.getType().getY());
135575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk        Allocation bitmapAlloc = Allocation.createTyped(sRS, tb_a8.create());
136a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray        greyConvert.forEach_RGBAtoA(bitmapTemp, bitmapAlloc);
137a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray
138a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray        return bitmapAlloc;
1397706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard    }
140a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray
1410055102404c767af2cd5fabf70acbc8317e33fe3Victor Doba    public Allocation loadScaledResourceAlpha(int resource, int inSampleSize) {
142575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk        Resources res = null;
143575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk        synchronized(ImageFilterRS.class) {
144575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk            res = sRS.getApplicationContext().getResources();
145575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk        }
14696df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        final BitmapFactory.Options options = new BitmapFactory.Options();
14796df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        options.inPreferredConfig = Bitmap.Config.ALPHA_8;
1480055102404c767af2cd5fabf70acbc8317e33fe3Victor Doba        options.inSampleSize      = inSampleSize;
14996df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        Bitmap bitmap = BitmapFactory.decodeResource(
150575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk                res,
15196df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard                resource, options);
15296df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        Allocation ret = convertRGBAtoA(bitmap);
15396df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        bitmap.recycle();
15496df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        return ret;
15596df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard    }
15696df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard
1570055102404c767af2cd5fabf70acbc8317e33fe3Victor Doba    public Allocation loadResourceAlpha(int resource) {
1580055102404c767af2cd5fabf70acbc8317e33fe3Victor Doba        return loadScaledResourceAlpha(resource, 1);
1590055102404c767af2cd5fabf70acbc8317e33fe3Victor Doba    }
1600055102404c767af2cd5fabf70acbc8317e33fe3Victor Doba
16196df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard    public Allocation loadResource(int resource) {
162575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk        Resources res = null;
163575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk        synchronized(ImageFilterRS.class) {
164575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk            res = sRS.getApplicationContext().getResources();
165575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk        }
16696df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        final BitmapFactory.Options options = new BitmapFactory.Options();
16796df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
16896df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        Bitmap bitmap = BitmapFactory.decodeResource(
169575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk                res,
17096df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard                resource, options);
17196df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        Allocation ret = convertBitmap(bitmap);
17296df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        bitmap.recycle();
17396df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        return ret;
17496df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard    }
17596df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard
176575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk    private boolean isResourcesLoaded() {
1777706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard        return mResourcesLoaded;
178a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray    }
179a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray
180575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk    private void setResourcesLoaded(boolean resourcesLoaded) {
1817706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard        mResourcesLoaded = resourcesLoaded;
1827706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard    }
1837706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard
184f79f954f4eb23bce55061c683a07fc7b3a965451Ruben Brunk    /**
185f79f954f4eb23bce55061c683a07fc7b3a965451Ruben Brunk     *  Bitmaps and RS Allocations should be cleared here
186f79f954f4eb23bce55061c683a07fc7b3a965451Ruben Brunk     */
1877706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard    abstract protected void resetAllocations();
1887706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard
189f79f954f4eb23bce55061c683a07fc7b3a965451Ruben Brunk    /**
190f79f954f4eb23bce55061c683a07fc7b3a965451Ruben Brunk     * RS Script objects (and all other RS objects) should be cleared here
191f79f954f4eb23bce55061c683a07fc7b3a965451Ruben Brunk     */
192f79f954f4eb23bce55061c683a07fc7b3a965451Ruben Brunk    abstract protected void resetScripts();
193f79f954f4eb23bce55061c683a07fc7b3a965451Ruben Brunk
1947706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard    public void freeResources() {
1957706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard        if (!isResourcesLoaded()) {
1967706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard            return;
1977706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard        }
198ea5355e6aa782bb61fbf079f4811873a67a83808Ruben Brunk        synchronized(ImageFilterRS.class) {
199ea5355e6aa782bb61fbf079f4811873a67a83808Ruben Brunk            resetAllocations();
200ea5355e6aa782bb61fbf079f4811873a67a83808Ruben Brunk            setResourcesLoaded(false);
201ea5355e6aa782bb61fbf079f4811873a67a83808Ruben Brunk        }
2027706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard    }
2035448bf8095483574649afcc2add7f153670c7450nicolasroard}
204