OSDN Git Service

am f007ac89: am 6cfb081c: G+ crop overlay shadows. Aspect ratios.
[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.cache.CachingPipeline;
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
33     public static boolean PERF_LOGGING = false;
34
35     private static ScriptC_grey mGreyConvert = null;
36     private static RenderScript mRScache = null;
37
38     private volatile boolean mResourcesLoaded = false;
39
40     protected abstract void createFilter(android.content.res.Resources res,
41             float scaleFactor, int quality);
42
43     protected void createFilter(android.content.res.Resources res,
44     float scaleFactor, int quality, Allocation in) {}
45     protected void bindScriptValues(Allocation in) {}
46
47     protected abstract void runFilter();
48
49     protected void update(Bitmap bitmap) {
50         getOutPixelsAllocation().copyTo(bitmap);
51     }
52
53     protected RenderScript getRenderScriptContext() {
54         return CachingPipeline.getRenderScriptContext();
55     }
56
57     protected Allocation getInPixelsAllocation() {
58         CachingPipeline pipeline = getEnvironment().getCachingPipeline();
59         return pipeline.getInPixelsAllocation();
60     }
61
62     protected Allocation getOutPixelsAllocation() {
63         CachingPipeline pipeline = getEnvironment().getCachingPipeline();
64         return pipeline.getOutPixelsAllocation();
65     }
66
67     @Override
68     public void apply(Allocation in, Allocation out) {
69         long startOverAll = System.nanoTime();
70         long startFilter = 0;
71         long endFilter = 0;
72         if (!mResourcesLoaded) {
73             CachingPipeline pipeline = getEnvironment().getCachingPipeline();
74             createFilter(pipeline.getResources(), getEnvironment().getScaleFactor(),
75                     getEnvironment().getQuality(), in);
76             mResourcesLoaded = true;
77         }
78         startFilter = System.nanoTime();
79         bindScriptValues(in);
80         run(in, out);
81         if (PERF_LOGGING) {
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);
93             Log.i(LOGTAG, msg);
94         }
95     }
96
97     protected void run(Allocation in, Allocation out) {}
98
99     @Override
100     public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) {
101         if (bitmap == null || bitmap.getWidth() == 0 || bitmap.getHeight() == 0) {
102             return bitmap;
103         }
104         try {
105             CachingPipeline pipeline = getEnvironment().getCachingPipeline();
106             if (DEBUG) {
107                 Log.v(LOGTAG, "apply filter " + getName() + " in pipeline " + pipeline.getName());
108             }
109             Resources rsc = pipeline.getResources();
110             boolean sizeChanged = false;
111             if (getInPixelsAllocation() != null
112                     && ((getInPixelsAllocation().getType().getX() != mLastInputWidth)
113                     || (getInPixelsAllocation().getType().getY() != mLastInputHeight))) {
114                 sizeChanged = true;
115             }
116             if (pipeline.prepareRenderscriptAllocations(bitmap)
117                     || !isResourcesLoaded() || sizeChanged) {
118                 freeResources();
119                 createFilter(rsc, scaleFactor, quality);
120                 setResourcesLoaded(true);
121                 mLastInputWidth = getInPixelsAllocation().getType().getX();
122                 mLastInputHeight = getInPixelsAllocation().getType().getY();
123             }
124             bindScriptValues();
125             runFilter();
126             update(bitmap);
127             if (DEBUG) {
128                 Log.v(LOGTAG, "DONE apply filter " + getName() + " in pipeline " + pipeline.getName());
129             }
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.
136             System.gc();
137             displayLowMemoryToast();
138             Log.e(LOGTAG, "not enough memory for filter " + getName(), e);
139         }
140
141         return bitmap;
142     }
143
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);
148     }
149
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(),
154                                             R.raw.grey);
155             mRScache = RS;
156         }
157
158         Type.Builder tb_a8 = new Type.Builder(RS, Element.A_8(RS));
159
160         Allocation bitmapTemp = convertBitmap(bitmap);
161         if (bitmapTemp.getType().getElement().isCompatible(Element.A_8(RS))) {
162             return bitmapTemp;
163         }
164
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();
172         return bitmapAlloc;
173     }
174
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(
181                 res,
182                 resource, options);
183         Allocation ret = convertRGBAtoA(bitmap);
184         bitmap.recycle();
185         return ret;
186     }
187
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(
194                 res,
195                 resource, options);
196         Bitmap resizeBitmap = Bitmap.createScaledBitmap(bitmap, w, h, true);
197         Allocation ret = convertRGBAtoA(resizeBitmap);
198         resizeBitmap.recycle();
199         bitmap.recycle();
200         return ret;
201     }
202
203     public Allocation loadResourceAlpha(int resource) {
204         return loadScaledResourceAlpha(resource, 1);
205     }
206
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(
212                 res,
213                 resource, options);
214         Allocation ret = convertBitmap(bitmap);
215         bitmap.recycle();
216         return ret;
217     }
218
219     private boolean isResourcesLoaded() {
220         return mResourcesLoaded;
221     }
222
223     private void setResourcesLoaded(boolean resourcesLoaded) {
224         mResourcesLoaded = resourcesLoaded;
225     }
226
227     /**
228      *  Bitmaps and RS Allocations should be cleared here
229      */
230     abstract protected void resetAllocations();
231
232     /**
233      * RS Script objects (and all other RS objects) should be cleared here
234      */
235     abstract protected void resetScripts();
236
237     /**
238      * Scripts values should be bound here
239      */
240     abstract protected void bindScriptValues();
241
242     public void freeResources() {
243         if (!isResourcesLoaded()) {
244             return;
245         }
246         resetAllocations();
247         setResourcesLoaded(false);
248     }
249 }