OSDN Git Service

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