ImageFilterRS.java revision 180277924bebf6b600ee5ce5adf9ff807a038570
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.gallery3d.filtershow.filters; 18 19import android.app.Activity; 20import android.graphics.Bitmap; 21import android.graphics.BitmapFactory; 22import android.support.v8.renderscript.*; 23import android.util.Log; 24import android.content.res.Resources; 25import com.android.gallery3d.R; 26import com.android.gallery3d.filtershow.cache.CachingPipeline; 27 28public abstract class ImageFilterRS extends ImageFilter { 29 private static final String LOGTAG = "ImageFilterRS"; 30 private boolean DEBUG = false; 31 32 private static volatile RenderScript sRS = null; 33 private static volatile Resources sResources = null; 34 private volatile boolean mResourcesLoaded = false; 35 36 // This must be used inside block synchronized on ImageFilterRS class object 37 protected abstract void createFilter(android.content.res.Resources res, 38 float scaleFactor, int quality); 39 40 // This must be used inside block synchronized on ImageFilterRS class object 41 protected abstract void runFilter(); 42 43 // This must be used inside block synchronized on ImageFilterRS class object 44 protected void update(Bitmap bitmap) { 45 getOutPixelsAllocation().copyTo(bitmap); 46 } 47 48 protected Allocation getInPixelsAllocation() { 49 CachingPipeline pipeline = getEnvironment().getCachingPipeline(); 50 return pipeline.getInPixelsAllocation(); 51 } 52 53 protected Allocation getOutPixelsAllocation() { 54 CachingPipeline pipeline = getEnvironment().getCachingPipeline(); 55 return pipeline.getOutPixelsAllocation(); 56 } 57 58 @Override 59 public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { 60 if (bitmap == null || bitmap.getWidth() == 0 || bitmap.getHeight() == 0) { 61 return bitmap; 62 } 63 try { 64 synchronized(ImageFilterRS.class) { 65 if (sRS == null) { 66 Log.w(LOGTAG, "Cannot apply before calling createRenderScriptContext"); 67 return bitmap; 68 } 69 CachingPipeline pipeline = getEnvironment().getCachingPipeline(); 70 if (DEBUG) { 71 Log.v(LOGTAG, "apply filter " + getName() + " in pipeline " + pipeline.getName()); 72 } 73 boolean needsUpdate = pipeline.prepareRenderscriptAllocations(bitmap); 74 if (needsUpdate || !isResourcesLoaded()) { 75 // the allocations changed size 76 freeResources(); 77 createFilter(sResources, scaleFactor, quality); 78 setResourcesLoaded(true); 79 } 80 runFilter(); 81 update(bitmap); 82 if (DEBUG) { 83 Log.v(LOGTAG, "DONE apply filter " + getName() + " in pipeline " + pipeline.getName()); 84 } 85 } 86 } catch (android.renderscript.RSIllegalArgumentException e) { 87 Log.e(LOGTAG, "Illegal argument? " + e); 88 } catch (android.renderscript.RSRuntimeException e) { 89 Log.e(LOGTAG, "RS runtime exception ? " + e); 90 } catch (java.lang.OutOfMemoryError e) { 91 // Many of the renderscript filters allocated large (>16Mb resources) in order to apply. 92 System.gc(); 93 displayLowMemoryToast(); 94 Log.e(LOGTAG, "not enough memory for filter " + getName(), e); 95 } 96 return bitmap; 97 } 98 99 public static synchronized RenderScript getRenderScriptContext() { 100 return sRS; 101 } 102 103 public static synchronized void createRenderscriptContext(Activity context) { 104 if( sRS != null) { 105 Log.w(LOGTAG, "A prior RS context exists when calling setRenderScriptContext"); 106 destroyRenderScriptContext(); 107 } 108 sRS = RenderScript.create(context); 109 sResources = context.getResources(); 110 } 111 112 public static synchronized void destroyRenderScriptContext() { 113 sRS.destroy(); 114 sRS = null; 115 sResources = null; 116 } 117 118 private static synchronized Allocation convertBitmap(Bitmap bitmap) { 119 return Allocation.createFromBitmap(sRS, bitmap, 120 Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT); 121 } 122 123 private static synchronized Allocation convertRGBAtoA(Bitmap bitmap) { 124 Type.Builder tb_a8 = new Type.Builder(sRS, Element.A_8(sRS)); 125 ScriptC_grey greyConvert = new ScriptC_grey(sRS, 126 sRS.getApplicationContext().getResources(), R.raw.grey); 127 128 Allocation bitmapTemp = convertBitmap(bitmap); 129 if (bitmapTemp.getType().getElement().isCompatible(Element.A_8(sRS))) { 130 return bitmapTemp; 131 } 132 133 tb_a8.setX(bitmapTemp.getType().getX()); 134 tb_a8.setY(bitmapTemp.getType().getY()); 135 Allocation bitmapAlloc = Allocation.createTyped(sRS, tb_a8.create()); 136 greyConvert.forEach_RGBAtoA(bitmapTemp, bitmapAlloc); 137 138 return bitmapAlloc; 139 } 140 141 public Allocation loadScaledResourceAlpha(int resource, int inSampleSize) { 142 Resources res = null; 143 synchronized(ImageFilterRS.class) { 144 res = sRS.getApplicationContext().getResources(); 145 } 146 final BitmapFactory.Options options = new BitmapFactory.Options(); 147 options.inPreferredConfig = Bitmap.Config.ALPHA_8; 148 options.inSampleSize = inSampleSize; 149 Bitmap bitmap = BitmapFactory.decodeResource( 150 res, 151 resource, options); 152 Allocation ret = convertRGBAtoA(bitmap); 153 bitmap.recycle(); 154 return ret; 155 } 156 157 public Allocation loadResourceAlpha(int resource) { 158 return loadScaledResourceAlpha(resource, 1); 159 } 160 161 public Allocation loadResource(int resource) { 162 Resources res = null; 163 synchronized(ImageFilterRS.class) { 164 res = sRS.getApplicationContext().getResources(); 165 } 166 final BitmapFactory.Options options = new BitmapFactory.Options(); 167 options.inPreferredConfig = Bitmap.Config.ARGB_8888; 168 Bitmap bitmap = BitmapFactory.decodeResource( 169 res, 170 resource, options); 171 Allocation ret = convertBitmap(bitmap); 172 bitmap.recycle(); 173 return ret; 174 } 175 176 private boolean isResourcesLoaded() { 177 return mResourcesLoaded; 178 } 179 180 private void setResourcesLoaded(boolean resourcesLoaded) { 181 mResourcesLoaded = resourcesLoaded; 182 } 183 184 /** 185 * Bitmaps and RS Allocations should be cleared here 186 */ 187 abstract protected void resetAllocations(); 188 189 /** 190 * RS Script objects (and all other RS objects) should be cleared here 191 */ 192 abstract protected void resetScripts(); 193 194 public void freeResources() { 195 if (!isResourcesLoaded()) { 196 return; 197 } 198 synchronized(ImageFilterRS.class) { 199 resetAllocations(); 200 setResourcesLoaded(false); 201 } 202 } 203} 204