ImageFilterRS.java revision 96df19b2a4b7286a01aeb690a38d8c99bc43449c
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;
24a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murrayimport com.android.gallery3d.R;
255448bf8095483574649afcc2add7f153670c7450nicolasroard
264e6c07b71b269ee3fe7f6fa455bc540238df9dedJohn Hofordpublic abstract class ImageFilterRS extends ImageFilter {
275448bf8095483574649afcc2add7f153670c7450nicolasroard    private final String LOGTAG = "ImageFilterRS";
285448bf8095483574649afcc2add7f153670c7450nicolasroard
295448bf8095483574649afcc2add7f153670c7450nicolasroard    private static RenderScript mRS = null;
305448bf8095483574649afcc2add7f153670c7450nicolasroard    protected static Allocation mInPixelsAllocation;
315448bf8095483574649afcc2add7f153670c7450nicolasroard    protected static Allocation mOutPixelsAllocation;
325448bf8095483574649afcc2add7f153670c7450nicolasroard    private static android.content.res.Resources mResources = null;
3357eedfd99676913f575b1f76e3a874026d1ddf7cnicolasroard    private static Bitmap sOldBitmap = null;
3457eedfd99676913f575b1f76e3a874026d1ddf7cnicolasroard    private Bitmap mOldBitmap = null;
355448bf8095483574649afcc2add7f153670c7450nicolasroard
367706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard    private boolean mResourcesLoaded = false;
377706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard
3857eedfd99676913f575b1f76e3a874026d1ddf7cnicolasroard    private final Bitmap.Config mBitmapConfig = Bitmap.Config.ARGB_8888;
3957eedfd99676913f575b1f76e3a874026d1ddf7cnicolasroard
40b01a32825018cfb79f2c965c1c3e3e25b5131229nicolasroard    public void resetBitmap() {
41b01a32825018cfb79f2c965c1c3e3e25b5131229nicolasroard        mOldBitmap = null;
42b01a32825018cfb79f2c965c1c3e3e25b5131229nicolasroard    }
43b01a32825018cfb79f2c965c1c3e3e25b5131229nicolasroard
4499baf61387ab1ef15bb9db5fa3b2b55591e87059John Hoford    public void prepare(Bitmap bitmap, float scaleFactor, int quality) {
4557eedfd99676913f575b1f76e3a874026d1ddf7cnicolasroard        if (sOldBitmap == null
4657eedfd99676913f575b1f76e3a874026d1ddf7cnicolasroard                || (bitmap.getWidth() != sOldBitmap.getWidth())
4757eedfd99676913f575b1f76e3a874026d1ddf7cnicolasroard                || (bitmap.getHeight() != sOldBitmap.getHeight())) {
4857eedfd99676913f575b1f76e3a874026d1ddf7cnicolasroard            if (mInPixelsAllocation != null) {
4957eedfd99676913f575b1f76e3a874026d1ddf7cnicolasroard                mInPixelsAllocation.destroy();
500f8047fe826a84829ab37bc7cd24c8a4dea0db64Ruben Brunk                mInPixelsAllocation = null;
5157eedfd99676913f575b1f76e3a874026d1ddf7cnicolasroard            }
5257eedfd99676913f575b1f76e3a874026d1ddf7cnicolasroard            if (mOutPixelsAllocation != null) {
5357eedfd99676913f575b1f76e3a874026d1ddf7cnicolasroard                mOutPixelsAllocation.destroy();
540f8047fe826a84829ab37bc7cd24c8a4dea0db64Ruben Brunk                mOutPixelsAllocation = null;
5557eedfd99676913f575b1f76e3a874026d1ddf7cnicolasroard            }
5657eedfd99676913f575b1f76e3a874026d1ddf7cnicolasroard            Bitmap bitmapBuffer = bitmap.copy(mBitmapConfig, true);
573df4f831396ffbc11e4bbee0b6150794e8e44e0bnicolasroard            mOutPixelsAllocation = Allocation.createFromBitmap(mRS, bitmapBuffer,
583df4f831396ffbc11e4bbee0b6150794e8e44e0bnicolasroard                    Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
5957eedfd99676913f575b1f76e3a874026d1ddf7cnicolasroard            mInPixelsAllocation = Allocation.createTyped(mRS,
6057eedfd99676913f575b1f76e3a874026d1ddf7cnicolasroard                    mOutPixelsAllocation.getType());
6157eedfd99676913f575b1f76e3a874026d1ddf7cnicolasroard            sOldBitmap = bitmap;
6263a7dac01d394523799939596b960cb03321798dJohn Hoford        }
6357eedfd99676913f575b1f76e3a874026d1ddf7cnicolasroard        mInPixelsAllocation.copyFrom(bitmap);
647706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard        if (mOldBitmap != sOldBitmap || !isResourcesLoaded()) {
657706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard            freeResources();
6699baf61387ab1ef15bb9db5fa3b2b55591e87059John Hoford            createFilter(mResources, scaleFactor, quality);
6757eedfd99676913f575b1f76e3a874026d1ddf7cnicolasroard            mOldBitmap = sOldBitmap;
687706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard            setResourcesLoaded(true);
6963a7dac01d394523799939596b960cb03321798dJohn Hoford        }
705448bf8095483574649afcc2add7f153670c7450nicolasroard    }
715448bf8095483574649afcc2add7f153670c7450nicolasroard
727706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard    abstract public void createFilter(android.content.res.Resources res,
737706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard            float scaleFactor, int quality);
745448bf8095483574649afcc2add7f153670c7450nicolasroard
757706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard    abstract public void runFilter();
765448bf8095483574649afcc2add7f153670c7450nicolasroard
775448bf8095483574649afcc2add7f153670c7450nicolasroard    public void update(Bitmap bitmap) {
785448bf8095483574649afcc2add7f153670c7450nicolasroard        mOutPixelsAllocation.copyTo(bitmap);
795448bf8095483574649afcc2add7f153670c7450nicolasroard    }
805448bf8095483574649afcc2add7f153670c7450nicolasroard
8181eb9976f967d9b3faa1749a8ab29d1743cf347dnicolasroard    @Override
8299baf61387ab1ef15bb9db5fa3b2b55591e87059John Hoford    public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) {
835448bf8095483574649afcc2add7f153670c7450nicolasroard        if (bitmap == null) {
8481eb9976f967d9b3faa1749a8ab29d1743cf347dnicolasroard            return bitmap;
855448bf8095483574649afcc2add7f153670c7450nicolasroard        }
865448bf8095483574649afcc2add7f153670c7450nicolasroard        try {
8799baf61387ab1ef15bb9db5fa3b2b55591e87059John Hoford            prepare(bitmap, scaleFactor, quality);
885448bf8095483574649afcc2add7f153670c7450nicolasroard            runFilter();
895448bf8095483574649afcc2add7f153670c7450nicolasroard            update(bitmap);
905448bf8095483574649afcc2add7f153670c7450nicolasroard        } catch (android.renderscript.RSIllegalArgumentException e) {
915448bf8095483574649afcc2add7f153670c7450nicolasroard            Log.e(LOGTAG, "Illegal argument? " + e);
925448bf8095483574649afcc2add7f153670c7450nicolasroard        } catch (android.renderscript.RSRuntimeException e) {
935448bf8095483574649afcc2add7f153670c7450nicolasroard            Log.e(LOGTAG, "RS runtime exception ? " + e);
94b17b1b0758799914fbad5f4a3afae71ce58891fcRuben Brunk        } catch (java.lang.OutOfMemoryError e) {
95b17b1b0758799914fbad5f4a3afae71ce58891fcRuben Brunk            // Many of the renderscript filters allocated large (>16Mb resources) in order to apply.
96b17b1b0758799914fbad5f4a3afae71ce58891fcRuben Brunk            System.gc();
97b17b1b0758799914fbad5f4a3afae71ce58891fcRuben Brunk            displayLowMemoryToast();
98b17b1b0758799914fbad5f4a3afae71ce58891fcRuben Brunk            Log.e(LOGTAG, "not enough memory for filter " + getName(), e);
995448bf8095483574649afcc2add7f153670c7450nicolasroard        }
10081eb9976f967d9b3faa1749a8ab29d1743cf347dnicolasroard        return bitmap;
1015448bf8095483574649afcc2add7f153670c7450nicolasroard    }
1025448bf8095483574649afcc2add7f153670c7450nicolasroard
1035448bf8095483574649afcc2add7f153670c7450nicolasroard    public static RenderScript getRenderScriptContext() {
1045448bf8095483574649afcc2add7f153670c7450nicolasroard        return mRS;
1055448bf8095483574649afcc2add7f153670c7450nicolasroard    }
1065448bf8095483574649afcc2add7f153670c7450nicolasroard
1075448bf8095483574649afcc2add7f153670c7450nicolasroard    public static void setRenderScriptContext(Activity context) {
1087921e124d57759d6f0887a42ddc360d923e60cddTim Murray        if (mRS == null) {
1097921e124d57759d6f0887a42ddc360d923e60cddTim Murray            mRS = RenderScript.create(context);
1107921e124d57759d6f0887a42ddc360d923e60cddTim Murray        }
1115448bf8095483574649afcc2add7f153670c7450nicolasroard        mResources = context.getResources();
112588c30c74178bc399b043a5401f0c1f93ae22378nicolasroard        if (mInPixelsAllocation != null) {
113588c30c74178bc399b043a5401f0c1f93ae22378nicolasroard            mInPixelsAllocation.destroy();
114588c30c74178bc399b043a5401f0c1f93ae22378nicolasroard            mInPixelsAllocation = null;
115588c30c74178bc399b043a5401f0c1f93ae22378nicolasroard        }
116588c30c74178bc399b043a5401f0c1f93ae22378nicolasroard        if (mOutPixelsAllocation != null) {
117588c30c74178bc399b043a5401f0c1f93ae22378nicolasroard            mOutPixelsAllocation.destroy();
118588c30c74178bc399b043a5401f0c1f93ae22378nicolasroard            mOutPixelsAllocation = null;
119588c30c74178bc399b043a5401f0c1f93ae22378nicolasroard        }
120588c30c74178bc399b043a5401f0c1f93ae22378nicolasroard        sOldBitmap = null;
1215448bf8095483574649afcc2add7f153670c7450nicolasroard    }
1225448bf8095483574649afcc2add7f153670c7450nicolasroard
12396df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard    private Allocation convertBitmap(Bitmap bitmap) {
12496df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        return Allocation.createFromBitmap(mRS, bitmap,
12596df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard                Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
12696df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard    }
12796df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard
12896df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard    private Allocation convertRGBAtoA(Bitmap bitmap) {
129a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray        Type.Builder tb_a8 = new Type.Builder(mRS, Element.U8(mRS));
130a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray        ScriptC_grey greyConvert = new ScriptC_grey(mRS, mResources, R.raw.grey);
131a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray
13296df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        Allocation bitmapTemp = convertBitmap(bitmap);
133a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray        if (bitmapTemp.getType().getElement().isCompatible(Element.U8(mRS))) {
134a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray            return bitmapTemp;
135a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray        }
136a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray
137a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray        tb_a8.setX(bitmapTemp.getType().getX());
138a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray        tb_a8.setY(bitmapTemp.getType().getY());
139a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray        Allocation bitmapAlloc = Allocation.createTyped(mRS, tb_a8.create());
140a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray        greyConvert.forEach_RGBAtoA(bitmapTemp, bitmapAlloc);
141a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray
142a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray        return bitmapAlloc;
1437706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard    }
144a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray
14596df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard    public Allocation loadResourceAlpha(int resource) {
14696df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        final BitmapFactory.Options options = new BitmapFactory.Options();
14796df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        options.inPreferredConfig = Bitmap.Config.ALPHA_8;
14896df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        Bitmap bitmap = BitmapFactory.decodeResource(
14996df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard                mRS.getApplicationContext().getResources(),
15096df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard                resource, options);
15196df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        Allocation ret = convertRGBAtoA(bitmap);
15296df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        bitmap.recycle();
15396df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        return ret;
15496df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard    }
15596df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard
15696df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard    public Allocation loadResource(int resource) {
15796df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        final BitmapFactory.Options options = new BitmapFactory.Options();
15896df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
15996df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        Bitmap bitmap = BitmapFactory.decodeResource(
16096df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard                mRS.getApplicationContext().getResources(),
16196df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard                resource, options);
16296df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        Allocation ret = convertBitmap(bitmap);
16396df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        bitmap.recycle();
16496df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard        return ret;
16596df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard    }
16696df19b2a4b7286a01aeb690a38d8c99bc43449cnicolasroard
1677706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard    public boolean isResourcesLoaded() {
1687706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard        return mResourcesLoaded;
169a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray    }
170a7723fb08098c0c7682b02cf459cafa3792a4ce4Tim Murray
1717706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard    public void setResourcesLoaded(boolean resourcesLoaded) {
1727706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard        mResourcesLoaded = resourcesLoaded;
1737706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard    }
1747706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard
1757706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard    abstract protected void resetAllocations();
1767706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard
1777706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard    public void freeResources() {
1787706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard        if (!isResourcesLoaded()) {
1797706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard            return;
1807706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard        }
1817706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard        resetAllocations();
1827706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard        setResourcesLoaded(false);
1837706e506dc74fa634a69b9ce8c7e5e2c457f01fcnicolasroard    }
1845448bf8095483574649afcc2add7f153670c7450nicolasroard}
185