OSDN Git Service

Merge remote-tracking branch 'origin/klp-dev-plus-aosp' into klp-dev-plus-aosp
[android-x86/packages-apps-Gallery2.git] / src / com / android / gallery3d / filtershow / filters / ImageFilterRS.java
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
17 package com.android.gallery3d.filtershow.filters;
18
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.pipeline.PipelineInterface;
26
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;
33
34     public static boolean PERF_LOGGING = false;
35
36     private static ScriptC_grey mGreyConvert = null;
37     private static RenderScript mRScache = null;
38
39     private volatile boolean mResourcesLoaded = false;
40
41     protected abstract void createFilter(android.content.res.Resources res,
42             float scaleFactor, int quality);
43
44     protected void createFilter(android.content.res.Resources res,
45     float scaleFactor, int quality, Allocation in) {}
46     protected void bindScriptValues(Allocation in) {}
47
48     protected abstract void runFilter();
49
50     protected void update(Bitmap bitmap) {
51         getOutPixelsAllocation().copyTo(bitmap);
52     }
53
54     protected RenderScript getRenderScriptContext() {
55         PipelineInterface pipeline = getEnvironment().getPipeline();
56         return pipeline.getRSContext();
57     }
58
59     protected Allocation getInPixelsAllocation() {
60         PipelineInterface pipeline = getEnvironment().getPipeline();
61         return pipeline.getInPixelsAllocation();
62     }
63
64     protected Allocation getOutPixelsAllocation() {
65         PipelineInterface pipeline = getEnvironment().getPipeline();
66         return pipeline.getOutPixelsAllocation();
67     }
68
69     @Override
70     public void apply(Allocation in, Allocation out) {
71         long startOverAll = System.nanoTime();
72         if (PERF_LOGGING) {
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);
78             Log.i(LOGTAG, msg);
79         }
80         mLastTimeCalled = startOverAll;
81         long startFilter = 0;
82         long endFilter = 0;
83         if (!mResourcesLoaded) {
84             PipelineInterface pipeline = getEnvironment().getPipeline();
85             createFilter(pipeline.getResources(), getEnvironment().getScaleFactor(),
86                     getEnvironment().getQuality(), in);
87             mResourcesLoaded = true;
88         }
89         startFilter = System.nanoTime();
90         bindScriptValues(in);
91         run(in, out);
92         if (PERF_LOGGING) {
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);
104             Log.i(LOGTAG, msg);
105         }
106     }
107
108     protected void run(Allocation in, Allocation out) {}
109
110     @Override
111     public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) {
112         if (bitmap == null || bitmap.getWidth() == 0 || bitmap.getHeight() == 0) {
113             return bitmap;
114         }
115         try {
116             PipelineInterface pipeline = getEnvironment().getPipeline();
117             if (DEBUG) {
118                 Log.v(LOGTAG, "apply filter " + getName() + " in pipeline " + pipeline.getName());
119             }
120             Resources rsc = pipeline.getResources();
121             boolean sizeChanged = false;
122             if (getInPixelsAllocation() != null
123                     && ((getInPixelsAllocation().getType().getX() != mLastInputWidth)
124                     || (getInPixelsAllocation().getType().getY() != mLastInputHeight))) {
125                 sizeChanged = true;
126             }
127             if (pipeline.prepareRenderscriptAllocations(bitmap)
128                     || !isResourcesLoaded() || sizeChanged) {
129                 freeResources();
130                 createFilter(rsc, scaleFactor, quality);
131                 setResourcesLoaded(true);
132                 mLastInputWidth = getInPixelsAllocation().getType().getX();
133                 mLastInputHeight = getInPixelsAllocation().getType().getY();
134             }
135             bindScriptValues();
136             runFilter();
137             update(bitmap);
138             if (DEBUG) {
139                 Log.v(LOGTAG, "DONE apply filter " + getName() + " in pipeline " + pipeline.getName());
140             }
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.
147             System.gc();
148             displayLowMemoryToast();
149             Log.e(LOGTAG, "not enough memory for filter " + getName(), e);
150         }
151         return bitmap;
152     }
153
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);
158     }
159
160     private static Allocation convertRGBAtoA(RenderScript RS, Bitmap bitmap) {
161         if (RS != mRScache || mGreyConvert == null) {
162             mGreyConvert = new ScriptC_grey(RS, RS.getApplicationContext().getResources(),
163                                             R.raw.grey);
164             mRScache = RS;
165         }
166
167         Type.Builder tb_a8 = new Type.Builder(RS, Element.A_8(RS));
168
169         Allocation bitmapTemp = convertBitmap(RS, bitmap);
170         if (bitmapTemp.getType().getElement().isCompatible(Element.A_8(RS))) {
171             return bitmapTemp;
172         }
173
174         tb_a8.setX(bitmapTemp.getType().getX());
175         tb_a8.setY(bitmapTemp.getType().getY());
176         Allocation bitmapAlloc = Allocation.createTyped(RS, tb_a8.create(),
177                                                         Allocation.MipmapControl.MIPMAP_NONE,
178                                                         Allocation.USAGE_SCRIPT | Allocation.USAGE_GRAPHICS_TEXTURE);
179         mGreyConvert.forEach_RGBAtoA(bitmapTemp, bitmapAlloc);
180         bitmapTemp.destroy();
181         return bitmapAlloc;
182     }
183
184     public Allocation loadScaledResourceAlpha(int resource, int inSampleSize) {
185         Resources res = getEnvironment().getPipeline().getResources();
186         final BitmapFactory.Options options = new BitmapFactory.Options();
187         options.inPreferredConfig = Bitmap.Config.ALPHA_8;
188         options.inSampleSize      = inSampleSize;
189         Bitmap bitmap = BitmapFactory.decodeResource(
190                 res,
191                 resource, options);
192         Allocation ret = convertRGBAtoA(getRenderScriptContext(), bitmap);
193         bitmap.recycle();
194         return ret;
195     }
196
197     public Allocation loadScaledResourceAlpha(int resource, int w, int h, int inSampleSize) {
198         Resources res = getEnvironment().getPipeline().getResources();
199         final BitmapFactory.Options options = new BitmapFactory.Options();
200         options.inPreferredConfig = Bitmap.Config.ALPHA_8;
201         options.inSampleSize      = inSampleSize;
202         Bitmap bitmap = BitmapFactory.decodeResource(
203                 res,
204                 resource, options);
205         Bitmap resizeBitmap = Bitmap.createScaledBitmap(bitmap, w, h, true);
206         Allocation ret = convertRGBAtoA(getRenderScriptContext(), resizeBitmap);
207         resizeBitmap.recycle();
208         bitmap.recycle();
209         return ret;
210     }
211
212     public Allocation loadResourceAlpha(int resource) {
213         return loadScaledResourceAlpha(resource, 1);
214     }
215
216     public Allocation loadResource(int resource) {
217         Resources res = getEnvironment().getPipeline().getResources();
218         final BitmapFactory.Options options = new BitmapFactory.Options();
219         options.inPreferredConfig = Bitmap.Config.ARGB_8888;
220         Bitmap bitmap = BitmapFactory.decodeResource(
221                 res,
222                 resource, options);
223         Allocation ret = convertBitmap(getRenderScriptContext(), bitmap);
224         bitmap.recycle();
225         return ret;
226     }
227
228     private boolean isResourcesLoaded() {
229         return mResourcesLoaded;
230     }
231
232     private void setResourcesLoaded(boolean resourcesLoaded) {
233         mResourcesLoaded = resourcesLoaded;
234     }
235
236     /**
237      *  Bitmaps and RS Allocations should be cleared here
238      */
239     abstract protected void resetAllocations();
240
241     /**
242      * RS Script objects (and all other RS objects) should be cleared here
243      */
244     public abstract void resetScripts();
245
246     /**
247      * Scripts values should be bound here
248      */
249     abstract protected void bindScriptValues();
250
251     public void freeResources() {
252         if (!isResourcesLoaded()) {
253             return;
254         }
255         resetAllocations();
256         mLastInputWidth = 0;
257         mLastInputHeight = 0;
258         setResourcesLoaded(false);
259     }
260 }