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