2 * Copyright (C) 2012 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.gallery3d.filtershow.filters;
19 import android.graphics.Bitmap;
20 import android.graphics.BitmapFactory;
21 import android.support.v8.renderscript.*;
22 import android.util.Log;
23 import android.content.res.Resources;
24 import com.android.gallery3d.R;
25 import com.android.gallery3d.filtershow.cache.CachingPipeline;
27 public abstract class ImageFilterRS extends ImageFilter {
28 private static final String LOGTAG = "ImageFilterRS";
29 private boolean DEBUG = false;
30 private int mLastInputWidth = 0;
31 private int mLastInputHeight = 0;
33 public static boolean PERF_LOGGING = false;
35 private static ScriptC_grey mGreyConvert = null;
36 private static RenderScript mRScache = null;
38 private volatile boolean mResourcesLoaded = false;
40 protected abstract void createFilter(android.content.res.Resources res,
41 float scaleFactor, int quality);
43 protected void createFilter(android.content.res.Resources res,
44 float scaleFactor, int quality, Allocation in) {}
45 protected void bindScriptValues(Allocation in) {}
47 protected abstract void runFilter();
49 protected void update(Bitmap bitmap) {
50 getOutPixelsAllocation().copyTo(bitmap);
53 protected RenderScript getRenderScriptContext() {
54 return CachingPipeline.getRenderScriptContext();
57 protected Allocation getInPixelsAllocation() {
58 CachingPipeline pipeline = getEnvironment().getCachingPipeline();
59 return pipeline.getInPixelsAllocation();
62 protected Allocation getOutPixelsAllocation() {
63 CachingPipeline pipeline = getEnvironment().getCachingPipeline();
64 return pipeline.getOutPixelsAllocation();
68 public void apply(Allocation in, Allocation out) {
69 long startOverAll = System.nanoTime();
72 if (!mResourcesLoaded) {
73 CachingPipeline pipeline = getEnvironment().getCachingPipeline();
74 createFilter(pipeline.getResources(), getEnvironment().getScaleFactor(),
75 getEnvironment().getQuality(), in);
76 mResourcesLoaded = true;
78 startFilter = System.nanoTime();
82 getRenderScriptContext().finish();
83 endFilter = System.nanoTime();
84 long endOverAll = System.nanoTime();
85 String msg = String.format("%s; image size %dx%d; ", getName(),
86 in.getType().getX(), in.getType().getY());
87 long timeOverAll = (endOverAll - startOverAll) / 1000;
88 long timeFilter = (endFilter - startFilter) / 1000;
89 msg += String.format("over all %.2f ms (%.2f FPS); ",
90 timeOverAll / 1000.f, 1000000.f / timeOverAll);
91 msg += String.format("run filter %.2f ms (%.2f FPS)",
92 timeFilter / 1000.f, 1000000.f / timeFilter);
97 protected void run(Allocation in, Allocation out) {}
100 public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) {
101 if (bitmap == null || bitmap.getWidth() == 0 || bitmap.getHeight() == 0) {
105 CachingPipeline pipeline = getEnvironment().getCachingPipeline();
107 Log.v(LOGTAG, "apply filter " + getName() + " in pipeline " + pipeline.getName());
109 Resources rsc = pipeline.getResources();
110 boolean sizeChanged = false;
111 if (getInPixelsAllocation() != null
112 && ((getInPixelsAllocation().getType().getX() != mLastInputWidth)
113 || (getInPixelsAllocation().getType().getY() != mLastInputHeight))) {
116 if (pipeline.prepareRenderscriptAllocations(bitmap)
117 || !isResourcesLoaded() || sizeChanged) {
119 createFilter(rsc, scaleFactor, quality);
120 setResourcesLoaded(true);
121 mLastInputWidth = getInPixelsAllocation().getType().getX();
122 mLastInputHeight = getInPixelsAllocation().getType().getY();
128 Log.v(LOGTAG, "DONE apply filter " + getName() + " in pipeline " + pipeline.getName());
130 } catch (android.renderscript.RSIllegalArgumentException e) {
131 Log.e(LOGTAG, "Illegal argument? " + e);
132 } catch (android.renderscript.RSRuntimeException e) {
133 Log.e(LOGTAG, "RS runtime exception ? " + e);
134 } catch (java.lang.OutOfMemoryError e) {
135 // Many of the renderscript filters allocated large (>16Mb resources) in order to apply.
137 displayLowMemoryToast();
138 Log.e(LOGTAG, "not enough memory for filter " + getName(), e);
144 protected static Allocation convertBitmap(Bitmap bitmap) {
145 return Allocation.createFromBitmap(CachingPipeline.getRenderScriptContext(), bitmap,
146 Allocation.MipmapControl.MIPMAP_NONE,
147 Allocation.USAGE_SCRIPT | Allocation.USAGE_GRAPHICS_TEXTURE);
150 private static Allocation convertRGBAtoA(Bitmap bitmap) {
151 RenderScript RS = CachingPipeline.getRenderScriptContext();
152 if (RS != mRScache || mGreyConvert == null) {
153 mGreyConvert = new ScriptC_grey(RS, RS.getApplicationContext().getResources(),
158 Type.Builder tb_a8 = new Type.Builder(RS, Element.A_8(RS));
160 Allocation bitmapTemp = convertBitmap(bitmap);
161 if (bitmapTemp.getType().getElement().isCompatible(Element.A_8(RS))) {
165 tb_a8.setX(bitmapTemp.getType().getX());
166 tb_a8.setY(bitmapTemp.getType().getY());
167 Allocation bitmapAlloc = Allocation.createTyped(RS, tb_a8.create(),
168 Allocation.MipmapControl.MIPMAP_NONE,
169 Allocation.USAGE_SCRIPT | Allocation.USAGE_GRAPHICS_TEXTURE);
170 mGreyConvert.forEach_RGBAtoA(bitmapTemp, bitmapAlloc);
171 bitmapTemp.destroy();
175 public Allocation loadScaledResourceAlpha(int resource, int inSampleSize) {
176 Resources res = CachingPipeline.getResources();
177 final BitmapFactory.Options options = new BitmapFactory.Options();
178 options.inPreferredConfig = Bitmap.Config.ALPHA_8;
179 options.inSampleSize = inSampleSize;
180 Bitmap bitmap = BitmapFactory.decodeResource(
183 Allocation ret = convertRGBAtoA(bitmap);
188 public Allocation loadScaledResourceAlpha(int resource, int w, int h, int inSampleSize) {
189 Resources res = CachingPipeline.getResources();
190 final BitmapFactory.Options options = new BitmapFactory.Options();
191 options.inPreferredConfig = Bitmap.Config.ALPHA_8;
192 options.inSampleSize = inSampleSize;
193 Bitmap bitmap = BitmapFactory.decodeResource(
196 Bitmap resizeBitmap = Bitmap.createScaledBitmap(bitmap, w, h, true);
197 Allocation ret = convertRGBAtoA(resizeBitmap);
198 resizeBitmap.recycle();
203 public Allocation loadResourceAlpha(int resource) {
204 return loadScaledResourceAlpha(resource, 1);
207 public Allocation loadResource(int resource) {
208 Resources res = CachingPipeline.getResources();
209 final BitmapFactory.Options options = new BitmapFactory.Options();
210 options.inPreferredConfig = Bitmap.Config.ARGB_8888;
211 Bitmap bitmap = BitmapFactory.decodeResource(
214 Allocation ret = convertBitmap(bitmap);
219 private boolean isResourcesLoaded() {
220 return mResourcesLoaded;
223 private void setResourcesLoaded(boolean resourcesLoaded) {
224 mResourcesLoaded = resourcesLoaded;
228 * Bitmaps and RS Allocations should be cleared here
230 abstract protected void resetAllocations();
233 * RS Script objects (and all other RS objects) should be cleared here
235 abstract protected void resetScripts();
238 * Scripts values should be bound here
240 abstract protected void bindScriptValues();
242 public void freeResources() {
243 if (!isResourcesLoaded()) {
247 setResourcesLoaded(false);