OSDN Git Service

Move classes to pipeline package
[android-x86/packages-apps-Gallery2.git] / src / com / android / gallery3d / filtershow / pipeline / CachingPipeline.java
1 /*
2  * Copyright (C) 2013 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.pipeline;
18
19 import android.app.Activity;
20 import android.content.res.Resources;
21 import android.graphics.Bitmap;
22 import android.support.v8.renderscript.Allocation;
23 import android.support.v8.renderscript.RenderScript;
24 import android.util.Log;
25
26 import com.android.gallery3d.filtershow.cache.ImageLoader;
27 import com.android.gallery3d.filtershow.filters.FiltersManager;
28 import com.android.gallery3d.filtershow.filters.ImageFilterGeometry;
29 import com.android.gallery3d.filtershow.imageshow.GeometryMetadata;
30 import com.android.gallery3d.filtershow.imageshow.MasterImage;
31
32 public class CachingPipeline implements PipelineInterface {
33     private static final String LOGTAG = "CachingPipeline";
34     private boolean DEBUG = false;
35
36     private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
37
38     private static volatile RenderScript sRS = null;
39     private static volatile Resources sResources = null;
40
41     private FiltersManager mFiltersManager = null;
42     private volatile Bitmap mOriginalBitmap = null;
43     private volatile Bitmap mResizedOriginalBitmap = null;
44
45     private FilterEnvironment mEnvironment = new FilterEnvironment();
46
47     private volatile Allocation mOriginalAllocation = null;
48     private volatile Allocation mFiltersOnlyOriginalAllocation =  null;
49
50     protected volatile Allocation mInPixelsAllocation;
51     protected volatile Allocation mOutPixelsAllocation;
52     private volatile int mWidth = 0;
53     private volatile int mHeight = 0;
54
55     private volatile GeometryMetadata mPreviousGeometry = null;
56     private volatile float mPreviewScaleFactor = 1.0f;
57     private volatile float mHighResPreviewScaleFactor = 1.0f;
58     private volatile String mName = "";
59
60     private ImageFilterGeometry mGeometry = null;
61
62     public CachingPipeline(FiltersManager filtersManager, String name) {
63         mFiltersManager = filtersManager;
64         mName = name;
65     }
66
67     public static synchronized RenderScript getRenderScriptContext() {
68         return sRS;
69     }
70
71     public static synchronized void createRenderscriptContext(Activity context) {
72         if (sRS != null) {
73             Log.w(LOGTAG, "A prior RS context exists when calling setRenderScriptContext");
74             destroyRenderScriptContext();
75         }
76         sRS = RenderScript.create(context);
77         sResources = context.getResources();
78     }
79
80     public static synchronized void destroyRenderScriptContext() {
81         if (sRS != null) {
82             sRS.destroy();
83         }
84         sRS = null;
85         sResources = null;
86     }
87
88     public void stop() {
89         mEnvironment.setStop(true);
90     }
91
92     public synchronized void reset() {
93         synchronized (CachingPipeline.class) {
94             if (getRenderScriptContext() == null) {
95                 return;
96             }
97             mOriginalBitmap = null; // just a reference to the bitmap in ImageLoader
98             if (mResizedOriginalBitmap != null) {
99                 mResizedOriginalBitmap.recycle();
100                 mResizedOriginalBitmap = null;
101             }
102             if (mOriginalAllocation != null) {
103                 mOriginalAllocation.destroy();
104                 mOriginalAllocation = null;
105             }
106             if (mFiltersOnlyOriginalAllocation != null) {
107                 mFiltersOnlyOriginalAllocation.destroy();
108                 mFiltersOnlyOriginalAllocation = null;
109             }
110             mPreviousGeometry = null;
111             mPreviewScaleFactor = 1.0f;
112             mHighResPreviewScaleFactor = 1.0f;
113
114             destroyPixelAllocations();
115         }
116     }
117
118     public Resources getResources() {
119         return sRS.getApplicationContext().getResources();
120     }
121
122     private synchronized void destroyPixelAllocations() {
123         if (DEBUG) {
124             Log.v(LOGTAG, "destroyPixelAllocations in " + getName());
125         }
126         if (mInPixelsAllocation != null) {
127             mInPixelsAllocation.destroy();
128             mInPixelsAllocation = null;
129         }
130         if (mOutPixelsAllocation != null) {
131             mOutPixelsAllocation.destroy();
132             mOutPixelsAllocation = null;
133         }
134         mWidth = 0;
135         mHeight = 0;
136     }
137
138     private String getType(RenderingRequest request) {
139         if (request.getType() == RenderingRequest.ICON_RENDERING) {
140             return "ICON_RENDERING";
141         }
142         if (request.getType() == RenderingRequest.FILTERS_RENDERING) {
143             return "FILTERS_RENDERING";
144         }
145         if (request.getType() == RenderingRequest.FULL_RENDERING) {
146             return "FULL_RENDERING";
147         }
148         if (request.getType() == RenderingRequest.GEOMETRY_RENDERING) {
149             return "GEOMETRY_RENDERING";
150         }
151         if (request.getType() == RenderingRequest.PARTIAL_RENDERING) {
152             return "PARTIAL_RENDERING";
153         }
154         if (request.getType() == RenderingRequest.HIGHRES_RENDERING) {
155             return "HIGHRES_RENDERING";
156         }
157         return "UNKNOWN TYPE!";
158     }
159
160     private void setupEnvironment(ImagePreset preset, boolean highResPreview) {
161         mEnvironment.setPipeline(this);
162         mEnvironment.setFiltersManager(mFiltersManager);
163         if (highResPreview) {
164             mEnvironment.setScaleFactor(mHighResPreviewScaleFactor);
165         } else {
166             mEnvironment.setScaleFactor(mPreviewScaleFactor);
167         }
168         mEnvironment.setQuality(FilterEnvironment.QUALITY_PREVIEW);
169         mEnvironment.setImagePreset(preset);
170         mEnvironment.setStop(false);
171     }
172
173     public void setOriginal(Bitmap bitmap) {
174         mOriginalBitmap = bitmap;
175         Log.v(LOGTAG,"setOriginal, size " + bitmap.getWidth() + " x " + bitmap.getHeight());
176         ImagePreset preset = MasterImage.getImage().getPreset();
177         setupEnvironment(preset, false);
178         updateOriginalAllocation(preset);
179     }
180
181     private synchronized boolean updateOriginalAllocation(ImagePreset preset) {
182         Bitmap originalBitmap = mOriginalBitmap;
183
184         if (originalBitmap == null) {
185             return false;
186         }
187
188         GeometryMetadata geometry = preset.getGeometry();
189         if (mPreviousGeometry != null && geometry.equals(mPreviousGeometry)) {
190             return false;
191         }
192
193         if (DEBUG) {
194             Log.v(LOGTAG, "geometry has changed");
195         }
196
197         RenderScript RS = getRenderScriptContext();
198
199         Allocation filtersOnlyOriginalAllocation = mFiltersOnlyOriginalAllocation;
200         mFiltersOnlyOriginalAllocation = Allocation.createFromBitmap(RS, originalBitmap,
201                 Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
202         if (filtersOnlyOriginalAllocation != null) {
203             filtersOnlyOriginalAllocation.destroy();
204         }
205
206         Allocation originalAllocation = mOriginalAllocation;
207         mResizedOriginalBitmap = preset.applyGeometry(originalBitmap, mEnvironment);
208         mOriginalAllocation = Allocation.createFromBitmap(RS, mResizedOriginalBitmap,
209                 Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
210         if (originalAllocation != null) {
211             originalAllocation.destroy();
212         }
213
214         mPreviousGeometry = new GeometryMetadata(geometry);
215         return true;
216     }
217
218     public synchronized void render(RenderingRequest request) {
219         synchronized (CachingPipeline.class) {
220             if (getRenderScriptContext() == null) {
221                 return;
222             }
223             if (((request.getType() != RenderingRequest.PARTIAL_RENDERING
224                     && request.getType() != RenderingRequest.HIGHRES_RENDERING)
225                     && request.getBitmap() == null)
226                     || request.getImagePreset() == null) {
227                 return;
228             }
229
230             if (DEBUG) {
231                 Log.v(LOGTAG, "render image of type " + getType(request));
232             }
233
234             Bitmap bitmap = request.getBitmap();
235             ImagePreset preset = request.getImagePreset();
236             setupEnvironment(preset,
237                     request.getType() != RenderingRequest.HIGHRES_RENDERING);
238             mFiltersManager.freeFilterResources(preset);
239
240             if (request.getType() == RenderingRequest.PARTIAL_RENDERING) {
241                 ImageLoader loader = MasterImage.getImage().getImageLoader();
242                 if (loader == null) {
243                     Log.w(LOGTAG, "loader not yet setup, cannot handle: " + getType(request));
244                     return;
245                 }
246                 bitmap = loader.getScaleOneImageForPreset(request.getBounds(),
247                         request.getDestination());
248                 if (bitmap == null) {
249                     Log.w(LOGTAG, "could not get bitmap for: " + getType(request));
250                     return;
251                 }
252             }
253
254             if (request.getType() == RenderingRequest.HIGHRES_RENDERING) {
255                 ImageLoader loader = MasterImage.getImage().getImageLoader();
256                 bitmap = loader.getOriginalBitmapHighres();
257                 if (bitmap != null) {
258                     bitmap = preset.applyGeometry(bitmap, mEnvironment);
259                 }
260             }
261
262             if (request.getType() == RenderingRequest.FULL_RENDERING
263                     || request.getType() == RenderingRequest.GEOMETRY_RENDERING
264                     || request.getType() == RenderingRequest.FILTERS_RENDERING) {
265                 updateOriginalAllocation(preset);
266             }
267
268             if (DEBUG) {
269                 Log.v(LOGTAG, "after update, req bitmap (" + bitmap.getWidth() + "x" + bitmap.getHeight()
270                         + " ? resizeOriginal (" + mResizedOriginalBitmap.getWidth() + "x"
271                         + mResizedOriginalBitmap.getHeight());
272             }
273
274             if (request.getType() == RenderingRequest.FULL_RENDERING
275                     || request.getType() == RenderingRequest.GEOMETRY_RENDERING) {
276                 mOriginalAllocation.copyTo(bitmap);
277             } else if (request.getType() == RenderingRequest.FILTERS_RENDERING) {
278                 mFiltersOnlyOriginalAllocation.copyTo(bitmap);
279             }
280
281             if (request.getType() == RenderingRequest.FULL_RENDERING
282                     || request.getType() == RenderingRequest.FILTERS_RENDERING
283                     || request.getType() == RenderingRequest.ICON_RENDERING
284                     || request.getType() == RenderingRequest.PARTIAL_RENDERING
285                     || request.getType() == RenderingRequest.HIGHRES_RENDERING
286                     || request.getType() == RenderingRequest.STYLE_ICON_RENDERING) {
287
288                 if (request.getType() == RenderingRequest.ICON_RENDERING) {
289                     mEnvironment.setQuality(FilterEnvironment.QUALITY_ICON);
290                 } else {
291                     mEnvironment.setQuality(FilterEnvironment.QUALITY_PREVIEW);
292                 }
293
294                 Bitmap bmp = preset.apply(bitmap, mEnvironment);
295                 if (!mEnvironment.needsStop()) {
296                     request.setBitmap(bmp);
297                 }
298                 mFiltersManager.freeFilterResources(preset);
299             }
300         }
301     }
302
303     public synchronized void renderImage(ImagePreset preset, Allocation in, Allocation out) {
304         synchronized (CachingPipeline.class) {
305             if (getRenderScriptContext() == null) {
306                 return;
307             }
308             setupEnvironment(preset, false);
309             mFiltersManager.freeFilterResources(preset);
310             preset.applyFilters(-1, -1, in, out, mEnvironment);
311             boolean copyOut = false;
312             if (preset.nbFilters() > 0) {
313                 copyOut = true;
314             }
315             preset.applyBorder(in, out, copyOut, mEnvironment);
316         }
317     }
318
319     public synchronized Bitmap renderFinalImage(Bitmap bitmap, ImagePreset preset) {
320         synchronized (CachingPipeline.class) {
321             if (getRenderScriptContext() == null) {
322                 return bitmap;
323             }
324             setupEnvironment(preset, false);
325             mEnvironment.setQuality(FilterEnvironment.QUALITY_FINAL);
326             mEnvironment.setScaleFactor(1.0f);
327             mFiltersManager.freeFilterResources(preset);
328             bitmap = preset.applyGeometry(bitmap, mEnvironment);
329             bitmap = preset.apply(bitmap, mEnvironment);
330             return bitmap;
331         }
332     }
333
334     public Bitmap renderGeometryIcon(Bitmap bitmap, ImagePreset preset) {
335         // Called by RenderRequest on the main thread
336         // TODO: change this -- we should reuse a pool of bitmaps instead...
337         if (mGeometry == null) {
338             mGeometry = new ImageFilterGeometry();
339         }
340         mGeometry.useRepresentation(preset.getGeometry());
341         return mGeometry.apply(bitmap, mPreviewScaleFactor,
342                 FilterEnvironment.QUALITY_PREVIEW);
343     }
344
345     public synchronized void compute(SharedBuffer buffer, ImagePreset preset, int type) {
346         synchronized (CachingPipeline.class) {
347             if (getRenderScriptContext() == null) {
348                 return;
349             }
350             if (DEBUG) {
351                 Log.v(LOGTAG, "compute preset " + preset);
352                 preset.showFilters();
353             }
354
355             String thread = Thread.currentThread().getName();
356             long time = System.currentTimeMillis();
357             setupEnvironment(preset, false);
358             mFiltersManager.freeFilterResources(preset);
359
360             Bitmap resizedOriginalBitmap = mResizedOriginalBitmap;
361             if (updateOriginalAllocation(preset) || buffer.getProducer() == null) {
362                 resizedOriginalBitmap = mResizedOriginalBitmap;
363                 buffer.setProducer(resizedOriginalBitmap);
364                 mEnvironment.cache(buffer.getProducer());
365             }
366
367             Bitmap bitmap = buffer.getProducer().getBitmap();
368             long time2 = System.currentTimeMillis();
369
370             if (bitmap == null || (bitmap.getWidth() != resizedOriginalBitmap.getWidth())
371                     || (bitmap.getHeight() != resizedOriginalBitmap.getHeight())) {
372                 mEnvironment.cache(buffer.getProducer());
373                 buffer.setProducer(resizedOriginalBitmap);
374                 bitmap = buffer.getProducer().getBitmap();
375             }
376             mOriginalAllocation.copyTo(bitmap);
377
378             Bitmap tmpbitmap = preset.apply(bitmap, mEnvironment);
379             if (tmpbitmap != bitmap) {
380                 mEnvironment.cache(buffer.getProducer());
381                 buffer.setProducer(tmpbitmap);
382             }
383
384             mFiltersManager.freeFilterResources(preset);
385
386             time = System.currentTimeMillis() - time;
387             time2 = System.currentTimeMillis() - time2;
388             if (DEBUG) {
389                 Log.v(LOGTAG, "Applying type " + type + " filters to bitmap "
390                         + bitmap + " (" + bitmap.getWidth() + " x " + bitmap.getHeight()
391                         + ") took " + time + " ms, " + time2 + " ms for the filter, on thread " + thread);
392             }
393         }
394     }
395
396     public boolean needsRepaint() {
397         SharedBuffer buffer = MasterImage.getImage().getPreviewBuffer();
398         return buffer.checkRepaintNeeded();
399     }
400
401     public void setPreviewScaleFactor(float previewScaleFactor) {
402         mPreviewScaleFactor = previewScaleFactor;
403     }
404
405     public void setHighResPreviewScaleFactor(float highResPreviewScaleFactor) {
406         mHighResPreviewScaleFactor = highResPreviewScaleFactor;
407     }
408
409     public synchronized boolean isInitialized() {
410         return getRenderScriptContext() != null && mOriginalBitmap != null;
411     }
412
413     public boolean prepareRenderscriptAllocations(Bitmap bitmap) {
414         RenderScript RS = getRenderScriptContext();
415         boolean needsUpdate = false;
416         if (mOutPixelsAllocation == null || mInPixelsAllocation == null ||
417                 bitmap.getWidth() != mWidth || bitmap.getHeight() != mHeight) {
418             destroyPixelAllocations();
419             Bitmap bitmapBuffer = bitmap;
420             if (bitmap.getConfig() == null || bitmap.getConfig() != BITMAP_CONFIG) {
421                 bitmapBuffer = bitmap.copy(BITMAP_CONFIG, true);
422             }
423             mOutPixelsAllocation = Allocation.createFromBitmap(RS, bitmapBuffer,
424                     Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
425             mInPixelsAllocation = Allocation.createTyped(RS,
426                     mOutPixelsAllocation.getType());
427             needsUpdate = true;
428         }
429         if (RS != null) {
430             mInPixelsAllocation.copyFrom(bitmap);
431         }
432         if (bitmap.getWidth() != mWidth
433                 || bitmap.getHeight() != mHeight) {
434             mWidth = bitmap.getWidth();
435             mHeight = bitmap.getHeight();
436             needsUpdate = true;
437         }
438         if (DEBUG) {
439             Log.v(LOGTAG, "prepareRenderscriptAllocations: " + needsUpdate + " in " + getName());
440         }
441         return needsUpdate;
442     }
443
444     public synchronized Allocation getInPixelsAllocation() {
445         return mInPixelsAllocation;
446     }
447
448     public synchronized Allocation getOutPixelsAllocation() {
449         return mOutPixelsAllocation;
450     }
451
452     public String getName() {
453         return mName;
454     }
455
456     public RenderScript getRSContext() {
457         return CachingPipeline.getRenderScriptContext();
458     }
459 }