ImageFilterRS.java revision 0c90af2257105a289c19a355e33d4035bd1fc61f
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
32ea5355e6aa782bb61fbf079f4811873a67a83808Ruben Brunk    private volatile boolean mResourcesLoaded = false;
3357eedfd99676913f575b1f76e3a874026d1ddf7cnicolasroard
34ea5355e6aa782bb61fbf079f4811873a67a83808Ruben Brunk    protected abstract void createFilter(android.content.res.Resources res,
357706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard            float scaleFactor, int quality);
365448bf8095483574649afcc2add7f153670c7450nicolasroard
37ea5355e6aa782bb61fbf079f4811873a67a83808Ruben Brunk    protected abstract void runFilter();
385448bf8095483574649afcc2add7f153670c7450nicolasroard
39ea5355e6aa782bb61fbf079f4811873a67a83808Ruben Brunk    protected void update(Bitmap bitmap) {
40fc8a6a38c699c0d75fa29664d9aaa369d361c335nicolasroard        getOutPixelsAllocation().copyTo(bitmap);
41fc8a6a38c699c0d75fa29664d9aaa369d361c335nicolasroard    }
42fc8a6a38c699c0d75fa29664d9aaa369d361c335nicolasroard
43560f959b659bb510a6ac9a92831534c5dfcf16benicolasroard    protected RenderScript getRenderScriptContext() {
44560f959b659bb510a6ac9a92831534c5dfcf16benicolasroard        return CachingPipeline.getRenderScriptContext();
45560f959b659bb510a6ac9a92831534c5dfcf16benicolasroard    }
46560f959b659bb510a6ac9a92831534c5dfcf16benicolasroard
47fc8a6a38c699c0d75fa29664d9aaa369d361c335nicolasroard    protected Allocation getInPixelsAllocation() {
48fc8a6a38c699c0d75fa29664d9aaa369d361c335nicolasroard        CachingPipeline pipeline = getEnvironment().getCachingPipeline();
49fc8a6a38c699c0d75fa29664d9aaa369d361c335nicolasroard        return pipeline.getInPixelsAllocation();
50fc8a6a38c699c0d75fa29664d9aaa369d361c335nicolasroard    }
51fc8a6a38c699c0d75fa29664d9aaa369d361c335nicolasroard
52fc8a6a38c699c0d75fa29664d9aaa369d361c335nicolasroard    protected Allocation getOutPixelsAllocation() {
53fc8a6a38c699c0d75fa29664d9aaa369d361c335nicolasroard        CachingPipeline pipeline = getEnvironment().getCachingPipeline();
54fc8a6a38c699c0d75fa29664d9aaa369d361c335nicolasroard        return pipeline.getOutPixelsAllocation();
555448bf8095483574649afcc2add7f153670c7450nicolasroard    }
565448bf8095483574649afcc2add7f153670c7450nicolasroard
5781eb9976f967d9b3faa1749a8ab29d1743cf347dnicolasroard    @Override
5899baf61387ab1ef15bb9db5fa3b2b55591e87059John Hoford    public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) {
59575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk        if (bitmap == null || bitmap.getWidth() == 0 || bitmap.getHeight() == 0) {
6081eb9976f967d9b3faa1749a8ab29d1743cf347dnicolasroard            return bitmap;
615448bf8095483574649afcc2add7f153670c7450nicolasroard        }
625448bf8095483574649afcc2add7f153670c7450nicolasroard        try {
63560f959b659bb510a6ac9a92831534c5dfcf16benicolasroard            CachingPipeline pipeline = getEnvironment().getCachingPipeline();
64560f959b659bb510a6ac9a92831534c5dfcf16benicolasroard            if (DEBUG) {
65560f959b659bb510a6ac9a92831534c5dfcf16benicolasroard                Log.v(LOGTAG, "apply filter " + getName() + " in pipeline " + pipeline.getName());
66560f959b659bb510a6ac9a92831534c5dfcf16benicolasroard            }
67560f959b659bb510a6ac9a92831534c5dfcf16benicolasroard            Resources rsc = pipeline.getResources();
680c90af2257105a289c19a355e33d4035bd1fc61fnicolasroard            if (pipeline.prepareRenderscriptAllocations(bitmap)
690c90af2257105a289c19a355e33d4035bd1fc61fnicolasroard                    || !isResourcesLoaded()) {
700c90af2257105a289c19a355e33d4035bd1fc61fnicolasroard                freeResources();
710c90af2257105a289c19a355e33d4035bd1fc61fnicolasroard                createFilter(rsc, scaleFactor, quality);
720c90af2257105a289c19a355e33d4035bd1fc61fnicolasroard                setResourcesLoaded(true);
730c90af2257105a289c19a355e33d4035bd1fc61fnicolasroard            }
740c90af2257105a289c19a355e33d4035bd1fc61fnicolasroard            bindScriptValues();
75560f959b659bb510a6ac9a92831534c5dfcf16benicolasroard            runFilter();
76560f959b659bb510a6ac9a92831534c5dfcf16benicolasroard            update(bitmap);
77560f959b659bb510a6ac9a92831534c5dfcf16benicolasroard            if (DEBUG) {
78560f959b659bb510a6ac9a92831534c5dfcf16benicolasroard                Log.v(LOGTAG, "DONE apply filter " + getName() + " in pipeline " + pipeline.getName());
79575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk            }
805448bf8095483574649afcc2add7f153670c7450nicolasroard        } catch (android.renderscript.RSIllegalArgumentException e) {
815448bf8095483574649afcc2add7f153670c7450nicolasroard            Log.e(LOGTAG, "Illegal argument? " + e);
825448bf8095483574649afcc2add7f153670c7450nicolasroard        } catch (android.renderscript.RSRuntimeException e) {
835448bf8095483574649afcc2add7f153670c7450nicolasroard            Log.e(LOGTAG, "RS runtime exception ? " + e);
84b17b1b0758799914fbad5f4a3afae71ce58891fcRuben Brunk        } catch (java.lang.OutOfMemoryError e) {
85b17b1b0758799914fbad5f4a3afae71ce58891fcRuben Brunk            // Many of the renderscript filters allocated large (>16Mb resources) in order to apply.
86b17b1b0758799914fbad5f4a3afae71ce58891fcRuben Brunk            System.gc();
87b17b1b0758799914fbad5f4a3afae71ce58891fcRuben Brunk            displayLowMemoryToast();
88b17b1b0758799914fbad5f4a3afae71ce58891fcRuben Brunk            Log.e(LOGTAG, "not enough memory for filter " + getName(), e);
895448bf8095483574649afcc2add7f153670c7450nicolasroard        }
9081eb9976f967d9b3faa1749a8ab29d1743cf347dnicolasroard        return bitmap;
915448bf8095483574649afcc2add7f153670c7450nicolasroard    }
925448bf8095483574649afcc2add7f153670c7450nicolasroard
93560f959b659bb510a6ac9a92831534c5dfcf16benicolasroard    private static Allocation convertBitmap(Bitmap bitmap) {
94560f959b659bb510a6ac9a92831534c5dfcf16benicolasroard        return Allocation.createFromBitmap(CachingPipeline.getRenderScriptContext(), bitmap,
9596df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard                Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
9696df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard    }
9796df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard
98560f959b659bb510a6ac9a92831534c5dfcf16benicolasroard    private static Allocation convertRGBAtoA(Bitmap bitmap) {
99560f959b659bb510a6ac9a92831534c5dfcf16benicolasroard        RenderScript RS = CachingPipeline.getRenderScriptContext();
100560f959b659bb510a6ac9a92831534c5dfcf16benicolasroard        Type.Builder tb_a8 = new Type.Builder(RS, Element.A_8(RS));
101560f959b659bb510a6ac9a92831534c5dfcf16benicolasroard        ScriptC_grey greyConvert = new ScriptC_grey(RS,
102560f959b659bb510a6ac9a92831534c5dfcf16benicolasroard                RS.getApplicationContext().getResources(), R.raw.grey);
103a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray
10496df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        Allocation bitmapTemp = convertBitmap(bitmap);
105560f959b659bb510a6ac9a92831534c5dfcf16benicolasroard        if (bitmapTemp.getType().getElement().isCompatible(Element.A_8(RS))) {
106a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray            return bitmapTemp;
107a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray        }
108a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray
109a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray        tb_a8.setX(bitmapTemp.getType().getX());
110a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray        tb_a8.setY(bitmapTemp.getType().getY());
111560f959b659bb510a6ac9a92831534c5dfcf16benicolasroard        Allocation bitmapAlloc = Allocation.createTyped(RS, tb_a8.create());
112a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray        greyConvert.forEach_RGBAtoA(bitmapTemp, bitmapAlloc);
113a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray
114a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray        return bitmapAlloc;
1157706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard    }
116a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray
1170055102404c767af2cd5fabf70acbc8317e33fe3Victor Doba    public Allocation loadScaledResourceAlpha(int resource, int inSampleSize) {
118560f959b659bb510a6ac9a92831534c5dfcf16benicolasroard        Resources res = CachingPipeline.getResources();
11996df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        final BitmapFactory.Options options = new BitmapFactory.Options();
12096df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        options.inPreferredConfig = Bitmap.Config.ALPHA_8;
1210055102404c767af2cd5fabf70acbc8317e33fe3Victor Doba        options.inSampleSize      = inSampleSize;
12296df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        Bitmap bitmap = BitmapFactory.decodeResource(
123575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk                res,
12496df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard                resource, options);
12596df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        Allocation ret = convertRGBAtoA(bitmap);
12696df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        bitmap.recycle();
12796df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        return ret;
12896df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard    }
12996df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard
1300055102404c767af2cd5fabf70acbc8317e33fe3Victor Doba    public Allocation loadResourceAlpha(int resource) {
1310055102404c767af2cd5fabf70acbc8317e33fe3Victor Doba        return loadScaledResourceAlpha(resource, 1);
1320055102404c767af2cd5fabf70acbc8317e33fe3Victor Doba    }
1330055102404c767af2cd5fabf70acbc8317e33fe3Victor Doba
13496df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard    public Allocation loadResource(int resource) {
135560f959b659bb510a6ac9a92831534c5dfcf16benicolasroard        Resources res = CachingPipeline.getResources();
13696df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        final BitmapFactory.Options options = new BitmapFactory.Options();
13796df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
13896df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        Bitmap bitmap = BitmapFactory.decodeResource(
139575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk                res,
14096df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard                resource, options);
14196df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        Allocation ret = convertBitmap(bitmap);
14296df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        bitmap.recycle();
14396df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        return ret;
14496df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard    }
14596df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard
146575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk    private boolean isResourcesLoaded() {
1477706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard        return mResourcesLoaded;
148a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray    }
149a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray
150575ce6f72fd87a62af1686edb3f17c0041031b86Ruben Brunk    private void setResourcesLoaded(boolean resourcesLoaded) {
1517706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard        mResourcesLoaded = resourcesLoaded;
1527706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard    }
1537706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard
154f79f954f4eb23bce55061c683a07fc7b3a965451Ruben Brunk    /**
155f79f954f4eb23bce55061c683a07fc7b3a965451Ruben Brunk     *  Bitmaps and RS Allocations should be cleared here
156f79f954f4eb23bce55061c683a07fc7b3a965451Ruben Brunk     */
1577706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard    abstract protected void resetAllocations();
1587706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard
159f79f954f4eb23bce55061c683a07fc7b3a965451Ruben Brunk    /**
160f79f954f4eb23bce55061c683a07fc7b3a965451Ruben Brunk     * RS Script objects (and all other RS objects) should be cleared here
161f79f954f4eb23bce55061c683a07fc7b3a965451Ruben Brunk     */
162f79f954f4eb23bce55061c683a07fc7b3a965451Ruben Brunk    abstract protected void resetScripts();
163f79f954f4eb23bce55061c683a07fc7b3a965451Ruben Brunk
1640c90af2257105a289c19a355e33d4035bd1fc61fnicolasroard    /**
1650c90af2257105a289c19a355e33d4035bd1fc61fnicolasroard     * Scripts values should be bound here
1660c90af2257105a289c19a355e33d4035bd1fc61fnicolasroard     */
1670c90af2257105a289c19a355e33d4035bd1fc61fnicolasroard    abstract protected void bindScriptValues();
1680c90af2257105a289c19a355e33d4035bd1fc61fnicolasroard
1697706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard    public void freeResources() {
1707706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard        if (!isResourcesLoaded()) {
1717706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard            return;
1727706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard        }
173560f959b659bb510a6ac9a92831534c5dfcf16benicolasroard        resetAllocations();
174560f959b659bb510a6ac9a92831534c5dfcf16benicolasroard        setResourcesLoaded(false);
1757706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard    }
1765448bf8095483574649afcc2add7f153670c7450nicolasroard}
177