OSDN Git Service

a7580a8359cb21a91897e7aa4547d65ad0b1bef1
[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                 MasterImage master = MasterImage.getImage();
242                 bitmap = ImageLoader.getScaleOneImageForPreset(master.getActivity(),
243                         master.getUri(), request.getBounds(),
244                         request.getDestination());
245                 if (bitmap == null) {
246                     Log.w(LOGTAG, "could not get bitmap for: " + getType(request));
247                     return;
248                 }
249             }
250
251             if (request.getType() == RenderingRequest.HIGHRES_RENDERING) {
252                 bitmap = MasterImage.getImage().getOriginalBitmapHighres();
253                 if (bitmap != null) {
254                     bitmap = preset.applyGeometry(bitmap, mEnvironment);
255                 }
256             }
257
258             if (request.getType() == RenderingRequest.FULL_RENDERING
259                     || request.getType() == RenderingRequest.GEOMETRY_RENDERING
260                     || request.getType() == RenderingRequest.FILTERS_RENDERING) {
261                 updateOriginalAllocation(preset);
262             }
263
264             if (DEBUG) {
265                 Log.v(LOGTAG, "after update, req bitmap (" + bitmap.getWidth() + "x" + bitmap.getHeight()
266                         + " ? resizeOriginal (" + mResizedOriginalBitmap.getWidth() + "x"
267                         + mResizedOriginalBitmap.getHeight());
268             }
269
270             if (request.getType() == RenderingRequest.FULL_RENDERING
271                     || request.getType() == RenderingRequest.GEOMETRY_RENDERING) {
272                 mOriginalAllocation.copyTo(bitmap);
273             } else if (request.getType() == RenderingRequest.FILTERS_RENDERING) {
274                 mFiltersOnlyOriginalAllocation.copyTo(bitmap);
275             }
276
277             if (request.getType() == RenderingRequest.FULL_RENDERING
278                     || request.getType() == RenderingRequest.FILTERS_RENDERING
279                     || request.getType() == RenderingRequest.ICON_RENDERING
280                     || request.getType() == RenderingRequest.PARTIAL_RENDERING
281                     || request.getType() == RenderingRequest.HIGHRES_RENDERING
282                     || request.getType() == RenderingRequest.STYLE_ICON_RENDERING) {
283
284                 if (request.getType() == RenderingRequest.ICON_RENDERING) {
285                     mEnvironment.setQuality(FilterEnvironment.QUALITY_ICON);
286                 } else {
287                     mEnvironment.setQuality(FilterEnvironment.QUALITY_PREVIEW);
288                 }
289
290                 Bitmap bmp = preset.apply(bitmap, mEnvironment);
291                 if (!mEnvironment.needsStop()) {
292                     request.setBitmap(bmp);
293                 }
294                 mFiltersManager.freeFilterResources(preset);
295             }
296         }
297     }
298
299     public synchronized void renderImage(ImagePreset preset, Allocation in, Allocation out) {
300         synchronized (CachingPipeline.class) {
301             if (getRenderScriptContext() == null) {
302                 return;
303             }
304             setupEnvironment(preset, false);
305             mFiltersManager.freeFilterResources(preset);
306             preset.applyFilters(-1, -1, in, out, mEnvironment);
307             boolean copyOut = false;
308             if (preset.nbFilters() > 0) {
309                 copyOut = true;
310             }
311             preset.applyBorder(in, out, copyOut, mEnvironment);
312         }
313     }
314
315     public synchronized Bitmap renderFinalImage(Bitmap bitmap, ImagePreset preset) {
316         synchronized (CachingPipeline.class) {
317             if (getRenderScriptContext() == null) {
318                 return bitmap;
319             }
320             setupEnvironment(preset, false);
321             mEnvironment.setQuality(FilterEnvironment.QUALITY_FINAL);
322             mEnvironment.setScaleFactor(1.0f);
323             mFiltersManager.freeFilterResources(preset);
324             bitmap = preset.applyGeometry(bitmap, mEnvironment);
325             bitmap = preset.apply(bitmap, mEnvironment);
326             return bitmap;
327         }
328     }
329
330     public Bitmap renderGeometryIcon(Bitmap bitmap, ImagePreset preset) {
331         // Called by RenderRequest on the main thread
332         // TODO: change this -- we should reuse a pool of bitmaps instead...
333         if (mGeometry == null) {
334             mGeometry = new ImageFilterGeometry();
335         }
336         mGeometry.useRepresentation(preset.getGeometry());
337         return mGeometry.apply(bitmap, mPreviewScaleFactor,
338                 FilterEnvironment.QUALITY_PREVIEW);
339     }
340
341     public synchronized void compute(SharedBuffer buffer, ImagePreset preset, int type) {
342         synchronized (CachingPipeline.class) {
343             if (getRenderScriptContext() == null) {
344                 return;
345             }
346             if (DEBUG) {
347                 Log.v(LOGTAG, "compute preset " + preset);
348                 preset.showFilters();
349             }
350
351             String thread = Thread.currentThread().getName();
352             long time = System.currentTimeMillis();
353             setupEnvironment(preset, false);
354             mFiltersManager.freeFilterResources(preset);
355
356             Bitmap resizedOriginalBitmap = mResizedOriginalBitmap;
357             if (updateOriginalAllocation(preset) || buffer.getProducer() == null) {
358                 resizedOriginalBitmap = mResizedOriginalBitmap;
359                 buffer.setProducer(resizedOriginalBitmap);
360                 mEnvironment.cache(buffer.getProducer());
361             }
362
363             Bitmap bitmap = buffer.getProducer().getBitmap();
364             long time2 = System.currentTimeMillis();
365
366             if (bitmap == null || (bitmap.getWidth() != resizedOriginalBitmap.getWidth())
367                     || (bitmap.getHeight() != resizedOriginalBitmap.getHeight())) {
368                 mEnvironment.cache(buffer.getProducer());
369                 buffer.setProducer(resizedOriginalBitmap);
370                 bitmap = buffer.getProducer().getBitmap();
371             }
372             mOriginalAllocation.copyTo(bitmap);
373
374             Bitmap tmpbitmap = preset.apply(bitmap, mEnvironment);
375             if (tmpbitmap != bitmap) {
376                 mEnvironment.cache(buffer.getProducer());
377                 buffer.setProducer(tmpbitmap);
378             }
379
380             mFiltersManager.freeFilterResources(preset);
381
382             time = System.currentTimeMillis() - time;
383             time2 = System.currentTimeMillis() - time2;
384             if (DEBUG) {
385                 Log.v(LOGTAG, "Applying type " + type + " filters to bitmap "
386                         + bitmap + " (" + bitmap.getWidth() + " x " + bitmap.getHeight()
387                         + ") took " + time + " ms, " + time2 + " ms for the filter, on thread " + thread);
388             }
389         }
390     }
391
392     public boolean needsRepaint() {
393         SharedBuffer buffer = MasterImage.getImage().getPreviewBuffer();
394         return buffer.checkRepaintNeeded();
395     }
396
397     public void setPreviewScaleFactor(float previewScaleFactor) {
398         mPreviewScaleFactor = previewScaleFactor;
399     }
400
401     public void setHighResPreviewScaleFactor(float highResPreviewScaleFactor) {
402         mHighResPreviewScaleFactor = highResPreviewScaleFactor;
403     }
404
405     public synchronized boolean isInitialized() {
406         return getRenderScriptContext() != null && mOriginalBitmap != null;
407     }
408
409     public boolean prepareRenderscriptAllocations(Bitmap bitmap) {
410         RenderScript RS = getRenderScriptContext();
411         boolean needsUpdate = false;
412         if (mOutPixelsAllocation == null || mInPixelsAllocation == null ||
413                 bitmap.getWidth() != mWidth || bitmap.getHeight() != mHeight) {
414             destroyPixelAllocations();
415             Bitmap bitmapBuffer = bitmap;
416             if (bitmap.getConfig() == null || bitmap.getConfig() != BITMAP_CONFIG) {
417                 bitmapBuffer = bitmap.copy(BITMAP_CONFIG, true);
418             }
419             mOutPixelsAllocation = Allocation.createFromBitmap(RS, bitmapBuffer,
420                     Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
421             mInPixelsAllocation = Allocation.createTyped(RS,
422                     mOutPixelsAllocation.getType());
423             needsUpdate = true;
424         }
425         if (RS != null) {
426             mInPixelsAllocation.copyFrom(bitmap);
427         }
428         if (bitmap.getWidth() != mWidth
429                 || bitmap.getHeight() != mHeight) {
430             mWidth = bitmap.getWidth();
431             mHeight = bitmap.getHeight();
432             needsUpdate = true;
433         }
434         if (DEBUG) {
435             Log.v(LOGTAG, "prepareRenderscriptAllocations: " + needsUpdate + " in " + getName());
436         }
437         return needsUpdate;
438     }
439
440     public synchronized Allocation getInPixelsAllocation() {
441         return mInPixelsAllocation;
442     }
443
444     public synchronized Allocation getOutPixelsAllocation() {
445         return mOutPixelsAllocation;
446     }
447
448     public String getName() {
449         return mName;
450     }
451
452     public RenderScript getRSContext() {
453         return CachingPipeline.getRenderScriptContext();
454     }
455 }