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.renderscript.*;
22 import android.util.Log;
23 import android.content.res.Resources;
24 import com.android.gallery3d.R;
25 import com.android.gallery3d.filtershow.pipeline.PipelineInterface;
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;
32 private long mLastTimeCalled;
34 public static boolean PERF_LOGGING = false;
36 private static ScriptC_grey mGreyConvert = null;
37 private static RenderScript mRScache = null;
39 private volatile boolean mResourcesLoaded = false;
41 protected abstract void createFilter(android.content.res.Resources res,
42 float scaleFactor, int quality);
44 protected void createFilter(android.content.res.Resources res,
45 float scaleFactor, int quality, Allocation in) {}
46 protected void bindScriptValues(Allocation in) {}
48 protected abstract void runFilter();
50 protected void update(Bitmap bitmap) {
51 getOutPixelsAllocation().copyTo(bitmap);
54 protected RenderScript getRenderScriptContext() {
55 PipelineInterface pipeline = getEnvironment().getPipeline();
56 return pipeline.getRSContext();
59 protected Allocation getInPixelsAllocation() {
60 PipelineInterface pipeline = getEnvironment().getPipeline();
61 return pipeline.getInPixelsAllocation();
64 protected Allocation getOutPixelsAllocation() {
65 PipelineInterface pipeline = getEnvironment().getPipeline();
66 return pipeline.getOutPixelsAllocation();
70 public void apply(Allocation in, Allocation out) {
71 long startOverAll = System.nanoTime();
73 long delay = (startOverAll - mLastTimeCalled) / 1000;
74 String msg = String.format("%s; image size %dx%d; ", getName(),
75 in.getType().getX(), in.getType().getY());
76 msg += String.format("called after %.2f ms (%.2f FPS); ",
77 delay / 1000.f, 1000000.f / delay);
80 mLastTimeCalled = startOverAll;
83 if (!mResourcesLoaded) {
84 PipelineInterface pipeline = getEnvironment().getPipeline();
85 createFilter(pipeline.getResources(), getEnvironment().getScaleFactor(),
86 getEnvironment().getQuality(), in);
87 mResourcesLoaded = true;
89 startFilter = System.nanoTime();
93 getRenderScriptContext().finish();
94 endFilter = System.nanoTime();
95 long endOverAll = System.nanoTime();
96 String msg = String.format("%s; image size %dx%d; ", getName(),
97 in.getType().getX(), in.getType().getY());
98 long timeOverAll = (endOverAll - startOverAll) / 1000;
99 long timeFilter = (endFilter - startFilter) / 1000;
100 msg += String.format("over all %.2f ms (%.2f FPS); ",
101 timeOverAll / 1000.f, 1000000.f / timeOverAll);
102 msg += String.format("run filter %.2f ms (%.2f FPS)",
103 timeFilter / 1000.f, 1000000.f / timeFilter);
108 protected void run(Allocation in, Allocation out) {}
111 public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) {
112 if (bitmap == null || bitmap.getWidth() == 0 || bitmap.getHeight() == 0) {
116 PipelineInterface pipeline = getEnvironment().getPipeline();
118 Log.v(LOGTAG, "apply filter " + getName() + " in pipeline " + pipeline.getName());
120 Resources rsc = pipeline.getResources();
121 boolean sizeChanged = false;
122 if (getInPixelsAllocation() != null
123 && ((getInPixelsAllocation().getType().getX() != mLastInputWidth)
124 || (getInPixelsAllocation().getType().getY() != mLastInputHeight))) {
127 if (pipeline.prepareRenderscriptAllocations(bitmap)
128 || !isResourcesLoaded() || sizeChanged) {
130 createFilter(rsc, scaleFactor, quality);
131 setResourcesLoaded(true);
132 mLastInputWidth = getInPixelsAllocation().getType().getX();
133 mLastInputHeight = getInPixelsAllocation().getType().getY();
139 Log.v(LOGTAG, "DONE apply filter " + getName() + " in pipeline " + pipeline.getName());
141 } catch (android.renderscript.RSIllegalArgumentException e) {
142 Log.e(LOGTAG, "Illegal argument? " + e);
143 } catch (android.renderscript.RSRuntimeException e) {
144 Log.e(LOGTAG, "RS runtime exception ? " + e);
145 } catch (java.lang.OutOfMemoryError e) {
146 // Many of the renderscript filters allocated large (>16Mb resources) in order to apply.
148 displayLowMemoryToast();
149 Log.e(LOGTAG, "not enough memory for filter " + getName(), e);
154 protected static Allocation convertBitmap(RenderScript RS, Bitmap bitmap) {
155 return Allocation.createFromBitmap(RS, bitmap,
156 Allocation.MipmapControl.MIPMAP_NONE,
157 Allocation.USAGE_SCRIPT | Allocation.USAGE_GRAPHICS_TEXTURE);
160 private static Allocation convertRGBAtoA(RenderScript RS, Bitmap bitmap) {
161 if (RS != mRScache || mGreyConvert == null) {
162 mGreyConvert = new ScriptC_grey(RS);
166 Type.Builder tb_a8 = new Type.Builder(RS, Element.A_8(RS));
168 Allocation bitmapTemp = convertBitmap(RS, bitmap);
169 if (bitmapTemp.getType().getElement().isCompatible(Element.A_8(RS))) {
173 tb_a8.setX(bitmapTemp.getType().getX());
174 tb_a8.setY(bitmapTemp.getType().getY());
175 Allocation bitmapAlloc = Allocation.createTyped(RS, tb_a8.create(),
176 Allocation.MipmapControl.MIPMAP_NONE,
177 Allocation.USAGE_SCRIPT | Allocation.USAGE_GRAPHICS_TEXTURE);
178 mGreyConvert.forEach_RGBAtoA(bitmapTemp, bitmapAlloc);
179 bitmapTemp.destroy();
183 public Allocation loadScaledResourceAlpha(int resource, int inSampleSize) {
184 Resources res = getEnvironment().getPipeline().getResources();
185 final BitmapFactory.Options options = new BitmapFactory.Options();
186 options.inSampleSize = inSampleSize;
187 Bitmap bitmap = BitmapFactory.decodeResource(
190 Allocation ret = convertRGBAtoA(getRenderScriptContext(), bitmap);
195 public Allocation loadScaledResourceAlpha(int resource, int w, int h, int inSampleSize) {
196 Resources res = getEnvironment().getPipeline().getResources();
197 final BitmapFactory.Options options = new BitmapFactory.Options();
198 options.inSampleSize = inSampleSize;
199 Bitmap bitmap = BitmapFactory.decodeResource(
202 Bitmap resizeBitmap = Bitmap.createScaledBitmap(bitmap, w, h, true);
203 Allocation ret = convertRGBAtoA(getRenderScriptContext(), resizeBitmap);
204 resizeBitmap.recycle();
209 public Allocation loadResourceAlpha(int resource) {
210 return loadScaledResourceAlpha(resource, 1);
213 public Allocation loadResource(int resource) {
214 Resources res = getEnvironment().getPipeline().getResources();
215 final BitmapFactory.Options options = new BitmapFactory.Options();
216 options.inPreferredConfig = Bitmap.Config.ARGB_8888;
217 Bitmap bitmap = BitmapFactory.decodeResource(
220 Allocation ret = convertBitmap(getRenderScriptContext(), bitmap);
225 private boolean isResourcesLoaded() {
226 return mResourcesLoaded;
229 private void setResourcesLoaded(boolean resourcesLoaded) {
230 mResourcesLoaded = resourcesLoaded;
234 * Bitmaps and RS Allocations should be cleared here
236 abstract protected void resetAllocations();
239 * RS Script objects (and all other RS objects) should be cleared here
241 public abstract void resetScripts();
244 * Scripts values should be bound here
246 abstract protected void bindScriptValues();
248 public void freeResources() {
249 if (!isResourcesLoaded()) {
254 mLastInputHeight = 0;
255 setResourcesLoaded(false);