OSDN Git Service

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