OSDN Git Service

4370013bc87027f5418b1eebba7494adcd2bd828
[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.content.Context;
20 import android.content.res.Resources;
21 import android.graphics.Bitmap;
22 import android.graphics.Canvas;
23 import android.graphics.Matrix;
24 import android.graphics.Paint;
25 import android.graphics.Rect;
26 import android.graphics.RectF;
27 import android.support.v8.renderscript.Allocation;
28 import android.support.v8.renderscript.RenderScript;
29 import android.util.Log;
30
31 import com.android.gallery3d.filtershow.cache.ImageLoader;
32 import com.android.gallery3d.filtershow.filters.FilterRepresentation;
33 import com.android.gallery3d.filtershow.filters.FiltersManager;
34 import com.android.gallery3d.filtershow.imageshow.GeometryMathUtils;
35 import com.android.gallery3d.filtershow.imageshow.MasterImage;
36
37 import java.util.Vector;
38
39 public class CachingPipeline implements PipelineInterface {
40     private static final String LOGTAG = "CachingPipeline";
41     private boolean DEBUG = false;
42
43     private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
44
45     private static volatile RenderScript sRS = null;
46
47     private FiltersManager mFiltersManager = null;
48     private volatile Bitmap mOriginalBitmap = null;
49     private volatile Bitmap mResizedOriginalBitmap = null;
50
51     private FilterEnvironment mEnvironment = new FilterEnvironment();
52     private CacheProcessing mCachedProcessing = new CacheProcessing();
53
54
55     private volatile Allocation mOriginalAllocation = null;
56     private volatile Allocation mFiltersOnlyOriginalAllocation =  null;
57
58     protected volatile Allocation mInPixelsAllocation;
59     protected volatile Allocation mOutPixelsAllocation;
60     private volatile int mWidth = 0;
61     private volatile int mHeight = 0;
62
63     private volatile float mPreviewScaleFactor = 1.0f;
64     private volatile float mHighResPreviewScaleFactor = 1.0f;
65     private volatile String mName = "";
66
67     public CachingPipeline(FiltersManager filtersManager, String name) {
68         mFiltersManager = filtersManager;
69         mName = name;
70     }
71
72     public static synchronized RenderScript getRenderScriptContext() {
73         return sRS;
74     }
75
76     public static synchronized void createRenderscriptContext(Context context) {
77         if (sRS != null) {
78             Log.w(LOGTAG, "A prior RS context exists when calling setRenderScriptContext");
79             destroyRenderScriptContext();
80         }
81         sRS = RenderScript.create(context);
82     }
83
84     public static synchronized void destroyRenderScriptContext() {
85         if (sRS != null) {
86             sRS.destroy();
87         }
88         sRS = 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             mPreviewScaleFactor = 1.0f;
114             mHighResPreviewScaleFactor = 1.0f;
115
116             destroyPixelAllocations();
117         }
118     }
119
120     public Resources getResources() {
121         return sRS.getApplicationContext().getResources();
122     }
123
124     private synchronized void destroyPixelAllocations() {
125         if (DEBUG) {
126             Log.v(LOGTAG, "destroyPixelAllocations in " + getName());
127         }
128         if (mInPixelsAllocation != null) {
129             mInPixelsAllocation.destroy();
130             mInPixelsAllocation = null;
131         }
132         if (mOutPixelsAllocation != null) {
133             mOutPixelsAllocation.destroy();
134             mOutPixelsAllocation = null;
135         }
136         mWidth = 0;
137         mHeight = 0;
138     }
139
140     private String getType(RenderingRequest request) {
141         if (request.getType() == RenderingRequest.ICON_RENDERING) {
142             return "ICON_RENDERING";
143         }
144         if (request.getType() == RenderingRequest.FILTERS_RENDERING) {
145             return "FILTERS_RENDERING";
146         }
147         if (request.getType() == RenderingRequest.FULL_RENDERING) {
148             return "FULL_RENDERING";
149         }
150         if (request.getType() == RenderingRequest.GEOMETRY_RENDERING) {
151             return "GEOMETRY_RENDERING";
152         }
153         if (request.getType() == RenderingRequest.PARTIAL_RENDERING) {
154             return "PARTIAL_RENDERING";
155         }
156         if (request.getType() == RenderingRequest.HIGHRES_RENDERING) {
157             return "HIGHRES_RENDERING";
158         }
159         return "UNKNOWN TYPE!";
160     }
161
162     private void setupEnvironment(ImagePreset preset, boolean highResPreview) {
163         mEnvironment.setPipeline(this);
164         mEnvironment.setFiltersManager(mFiltersManager);
165         mEnvironment.setBitmapCache(MasterImage.getImage().getBitmapCache());
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         if (preset == null) {
186             return false;
187         }
188         Bitmap originalBitmap = mOriginalBitmap;
189
190         if (originalBitmap == null) {
191             return false;
192         }
193
194         RenderScript RS = getRenderScriptContext();
195
196         Allocation filtersOnlyOriginalAllocation = mFiltersOnlyOriginalAllocation;
197         mFiltersOnlyOriginalAllocation = Allocation.createFromBitmap(RS, originalBitmap,
198                 Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
199         if (filtersOnlyOriginalAllocation != null) {
200             filtersOnlyOriginalAllocation.destroy();
201         }
202
203         Allocation originalAllocation = mOriginalAllocation;
204         mResizedOriginalBitmap = preset.applyGeometry(originalBitmap, mEnvironment);
205         mOriginalAllocation = Allocation.createFromBitmap(RS, mResizedOriginalBitmap,
206                 Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
207         if (originalAllocation != null) {
208             originalAllocation.destroy();
209         }
210
211         return true;
212     }
213
214     public void renderHighres(RenderingRequest request) {
215         synchronized (CachingPipeline.class) {
216             if (getRenderScriptContext() == null) {
217                 return;
218             }
219             ImagePreset preset = request.getImagePreset();
220             setupEnvironment(preset, false);
221             Bitmap bitmap = MasterImage.getImage().getOriginalBitmapHighres();
222             if (bitmap == null) {
223                 return;
224             }
225             bitmap = mEnvironment.getBitmapCopy(bitmap);
226             bitmap = preset.applyGeometry(bitmap, mEnvironment);
227
228             mEnvironment.setQuality(FilterEnvironment.QUALITY_PREVIEW);
229             Bitmap bmp = preset.apply(bitmap, mEnvironment);
230             if (!mEnvironment.needsStop()) {
231                 request.setBitmap(bmp);
232             } else {
233                 mEnvironment.cache(bmp);
234             }
235             mFiltersManager.freeFilterResources(preset);
236         }
237     }
238
239     public void renderGeometry(RenderingRequest request) {
240         synchronized (CachingPipeline.class) {
241             if (getRenderScriptContext() == null) {
242                 return;
243             }
244             ImagePreset preset = request.getImagePreset();
245             setupEnvironment(preset, false);
246             Bitmap bitmap = MasterImage.getImage().getOriginalBitmapHighres();
247             if (bitmap == null) {
248                 return;
249             }
250             bitmap = mEnvironment.getBitmapCopy(bitmap);
251             bitmap = preset.applyGeometry(bitmap, mEnvironment);
252             if (!mEnvironment.needsStop()) {
253                 request.setBitmap(bitmap);
254             } else {
255                 mEnvironment.cache(bitmap);
256             }
257             mFiltersManager.freeFilterResources(preset);
258         }
259     }
260
261     public void renderFilters(RenderingRequest request) {
262         synchronized (CachingPipeline.class) {
263             if (getRenderScriptContext() == null) {
264                 return;
265             }
266             ImagePreset preset = request.getImagePreset();
267             setupEnvironment(preset, false);
268             Bitmap bitmap = MasterImage.getImage().getOriginalBitmapHighres();
269             if (bitmap == null) {
270                 return;
271             }
272             bitmap = mEnvironment.getBitmapCopy(bitmap);
273             bitmap = preset.apply(bitmap, mEnvironment);
274             if (!mEnvironment.needsStop()) {
275                 request.setBitmap(bitmap);
276             } else {
277                 mEnvironment.cache(bitmap);
278             }
279             mFiltersManager.freeFilterResources(preset);
280         }
281     }
282
283     public synchronized void render(RenderingRequest request) {
284         // TODO: cleanup/remove GEOMETRY / FILTERS paths
285         synchronized (CachingPipeline.class) {
286             if (getRenderScriptContext() == null) {
287                 return;
288             }
289             if ((request.getType() != RenderingRequest.PARTIAL_RENDERING
290                   && request.getType() != RenderingRequest.ICON_RENDERING
291                     && request.getBitmap() == null)
292                     || request.getImagePreset() == null) {
293                 return;
294             }
295
296             if (DEBUG) {
297                 Log.v(LOGTAG, "render image of type " + getType(request));
298             }
299
300             Bitmap bitmap = request.getBitmap();
301             ImagePreset preset = request.getImagePreset();
302             setupEnvironment(preset, true);
303             mFiltersManager.freeFilterResources(preset);
304
305             if (request.getType() == RenderingRequest.PARTIAL_RENDERING) {
306                 MasterImage master = MasterImage.getImage();
307                 bitmap = ImageLoader.getScaleOneImageForPreset(master.getActivity(),
308                         mEnvironment,
309                         master.getUri(), request.getBounds(),
310                         request.getDestination());
311                 if (bitmap == null) {
312                     Log.w(LOGTAG, "could not get bitmap for: " + getType(request));
313                     return;
314                 }
315             }
316
317             if (request.getType() == RenderingRequest.FULL_RENDERING
318                     || request.getType() == RenderingRequest.GEOMETRY_RENDERING
319                     || request.getType() == RenderingRequest.FILTERS_RENDERING) {
320                 updateOriginalAllocation(preset);
321             }
322
323             if (DEBUG && bitmap != null) {
324                 Log.v(LOGTAG, "after update, req bitmap (" + bitmap.getWidth() + "x" + bitmap.getHeight()
325                         + " ? resizeOriginal (" + mResizedOriginalBitmap.getWidth() + "x"
326                         + mResizedOriginalBitmap.getHeight());
327             }
328
329             if (request.getType() == RenderingRequest.FULL_RENDERING
330                     || request.getType() == RenderingRequest.GEOMETRY_RENDERING) {
331                 mOriginalAllocation.copyTo(bitmap);
332             } else if (request.getType() == RenderingRequest.FILTERS_RENDERING) {
333                 mFiltersOnlyOriginalAllocation.copyTo(bitmap);
334             }
335
336             if (request.getType() == RenderingRequest.FULL_RENDERING
337                     || request.getType() == RenderingRequest.FILTERS_RENDERING
338                     || request.getType() == RenderingRequest.ICON_RENDERING
339                     || request.getType() == RenderingRequest.PARTIAL_RENDERING
340                     || request.getType() == RenderingRequest.STYLE_ICON_RENDERING) {
341
342                 if (request.getType() == RenderingRequest.ICON_RENDERING) {
343                     mEnvironment.setQuality(FilterEnvironment.QUALITY_ICON);
344                 } else {
345                     mEnvironment.setQuality(FilterEnvironment.QUALITY_PREVIEW);
346                 }
347
348                 if (request.getType() == RenderingRequest.ICON_RENDERING) {
349                     Rect iconBounds = request.getIconBounds();
350                     Bitmap source = MasterImage.getImage().getThumbnailBitmap();
351                     if (iconBounds.width() > source.getWidth() * 2) {
352                         source = MasterImage.getImage().getLargeThumbnailBitmap();
353                     }
354                     if (iconBounds != null) {
355                         bitmap = mEnvironment.getBitmap(iconBounds.width(), iconBounds.height());
356                         Canvas canvas = new Canvas(bitmap);
357                         Matrix m = new Matrix();
358                         float minSize = Math.min(source.getWidth(), source.getHeight());
359                         float maxSize = Math.max(iconBounds.width(), iconBounds.height());
360                         float scale = maxSize / minSize;
361                         m.setScale(scale, scale);
362                         float dx = (iconBounds.width() - (source.getWidth() * scale))/2.0f;
363                         float dy = (iconBounds.height() - (source.getHeight() * scale))/2.0f;
364                         m.postTranslate(dx, dy);
365                         canvas.drawBitmap(source, m, new Paint(Paint.FILTER_BITMAP_FLAG));
366                     } else {
367                         bitmap = mEnvironment.getBitmapCopy(source);
368                     }
369                 }
370                 Bitmap bmp = preset.apply(bitmap, mEnvironment);
371                 if (!mEnvironment.needsStop()) {
372                     request.setBitmap(bmp);
373                 }
374                 mFiltersManager.freeFilterResources(preset);
375             }
376         }
377     }
378
379     public synchronized void renderImage(ImagePreset preset, Allocation in, Allocation out) {
380         synchronized (CachingPipeline.class) {
381             if (getRenderScriptContext() == null) {
382                 return;
383             }
384             setupEnvironment(preset, false);
385             mFiltersManager.freeFilterResources(preset);
386             preset.applyFilters(-1, -1, in, out, mEnvironment);
387             boolean copyOut = false;
388             if (preset.nbFilters() > 0) {
389                 copyOut = true;
390             }
391             preset.applyBorder(in, out, copyOut, mEnvironment);
392         }
393     }
394
395     public synchronized Bitmap renderFinalImage(Bitmap bitmap, ImagePreset preset) {
396         synchronized (CachingPipeline.class) {
397             if (getRenderScriptContext() == null) {
398                 return bitmap;
399             }
400             setupEnvironment(preset, false);
401             mEnvironment.setQuality(FilterEnvironment.QUALITY_FINAL);
402             mEnvironment.setScaleFactor(1.0f);
403             mFiltersManager.freeFilterResources(preset);
404             bitmap = preset.applyGeometry(bitmap, mEnvironment);
405             bitmap = preset.apply(bitmap, mEnvironment);
406             return bitmap;
407         }
408     }
409
410     public Bitmap renderGeometryIcon(Bitmap bitmap, ImagePreset preset) {
411         return GeometryMathUtils.applyGeometryRepresentations(preset.getGeometryFilters(), bitmap);
412     }
413
414     public void compute(SharedBuffer buffer, ImagePreset preset, int type) {
415         if (getRenderScriptContext() == null) {
416             return;
417         }
418         setupEnvironment(preset, false);
419         Vector<FilterRepresentation> filters = preset.getFilters();
420         Bitmap result = mCachedProcessing.process(mOriginalBitmap, filters, mEnvironment);
421         buffer.setProducer(result);
422     }
423
424     public synchronized void computeOld(SharedBuffer buffer, ImagePreset preset, int type) {
425         synchronized (CachingPipeline.class) {
426             if (getRenderScriptContext() == null) {
427                 return;
428             }
429             if (DEBUG) {
430                 Log.v(LOGTAG, "compute preset " + preset);
431                 preset.showFilters();
432             }
433
434             String thread = Thread.currentThread().getName();
435             long time = System.currentTimeMillis();
436             setupEnvironment(preset, false);
437             mFiltersManager.freeFilterResources(preset);
438
439             Bitmap resizedOriginalBitmap = mResizedOriginalBitmap;
440             if (updateOriginalAllocation(preset) || buffer.getProducer() == null) {
441                 resizedOriginalBitmap = mResizedOriginalBitmap;
442                 buffer.setProducer(resizedOriginalBitmap);
443                 mEnvironment.cache(buffer.getProducer());
444             }
445
446             Bitmap bitmap = buffer.getProducer().getBitmap();
447             long time2 = System.currentTimeMillis();
448
449             if (bitmap == null || (bitmap.getWidth() != resizedOriginalBitmap.getWidth())
450                     || (bitmap.getHeight() != resizedOriginalBitmap.getHeight())) {
451                 mEnvironment.cache(buffer.getProducer());
452                 buffer.setProducer(resizedOriginalBitmap);
453                 bitmap = buffer.getProducer().getBitmap();
454             }
455             mOriginalAllocation.copyTo(bitmap);
456
457             Bitmap tmpbitmap = preset.apply(bitmap, mEnvironment);
458             if (tmpbitmap != bitmap) {
459                 mEnvironment.cache(buffer.getProducer());
460                 buffer.setProducer(tmpbitmap);
461             }
462
463             mFiltersManager.freeFilterResources(preset);
464
465             time = System.currentTimeMillis() - time;
466             time2 = System.currentTimeMillis() - time2;
467             if (DEBUG) {
468                 Log.v(LOGTAG, "Applying type " + type + " filters to bitmap "
469                         + bitmap + " (" + bitmap.getWidth() + " x " + bitmap.getHeight()
470                         + ") took " + time + " ms, " + time2 + " ms for the filter, on thread " + thread);
471             }
472         }
473     }
474
475     public boolean needsRepaint() {
476         SharedBuffer buffer = MasterImage.getImage().getPreviewBuffer();
477         return buffer.checkRepaintNeeded();
478     }
479
480     public void setPreviewScaleFactor(float previewScaleFactor) {
481         mPreviewScaleFactor = previewScaleFactor;
482     }
483
484     public void setHighResPreviewScaleFactor(float highResPreviewScaleFactor) {
485         mHighResPreviewScaleFactor = highResPreviewScaleFactor;
486     }
487
488     public synchronized boolean isInitialized() {
489         return getRenderScriptContext() != null && mOriginalBitmap != null;
490     }
491
492     public boolean prepareRenderscriptAllocations(Bitmap bitmap) {
493         RenderScript RS = getRenderScriptContext();
494         boolean needsUpdate = false;
495         if (mOutPixelsAllocation == null || mInPixelsAllocation == null ||
496                 bitmap.getWidth() != mWidth || bitmap.getHeight() != mHeight) {
497             destroyPixelAllocations();
498             Bitmap bitmapBuffer = bitmap;
499             if (bitmap.getConfig() == null || bitmap.getConfig() != BITMAP_CONFIG) {
500                 bitmapBuffer = bitmap.copy(BITMAP_CONFIG, true);
501             }
502             mOutPixelsAllocation = Allocation.createFromBitmap(RS, bitmapBuffer,
503                     Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
504             mInPixelsAllocation = Allocation.createTyped(RS,
505                     mOutPixelsAllocation.getType());
506             needsUpdate = true;
507         }
508         if (RS != null) {
509             mInPixelsAllocation.copyFrom(bitmap);
510         }
511         if (bitmap.getWidth() != mWidth
512                 || bitmap.getHeight() != mHeight) {
513             mWidth = bitmap.getWidth();
514             mHeight = bitmap.getHeight();
515             needsUpdate = true;
516         }
517         if (DEBUG) {
518             Log.v(LOGTAG, "prepareRenderscriptAllocations: " + needsUpdate + " in " + getName());
519         }
520         return needsUpdate;
521     }
522
523     public synchronized Allocation getInPixelsAllocation() {
524         return mInPixelsAllocation;
525     }
526
527     public synchronized Allocation getOutPixelsAllocation() {
528         return mOutPixelsAllocation;
529     }
530
531     public String getName() {
532         return mName;
533     }
534
535     public RenderScript getRSContext() {
536         return CachingPipeline.getRenderScriptContext();
537     }
538 }