2 * Copyright (C) 2013 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.gallery3d.filtershow.pipeline;
19 import android.content.Context;
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;
26 import com.android.gallery3d.filtershow.cache.ImageLoader;
27 import com.android.gallery3d.filtershow.filters.FilterRepresentation;
28 import com.android.gallery3d.filtershow.filters.FiltersManager;
29 import com.android.gallery3d.filtershow.imageshow.GeometryMathUtils;
30 import com.android.gallery3d.filtershow.imageshow.MasterImage;
32 import java.util.Vector;
34 public class CachingPipeline implements PipelineInterface {
35 private static final String LOGTAG = "CachingPipeline";
36 private boolean DEBUG = false;
38 private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
40 private static volatile RenderScript sRS = null;
42 private FiltersManager mFiltersManager = null;
43 private volatile Bitmap mOriginalBitmap = null;
44 private volatile Bitmap mResizedOriginalBitmap = null;
46 private FilterEnvironment mEnvironment = new FilterEnvironment();
47 private CacheProcessing mCachedProcessing = new CacheProcessing();
50 private volatile Allocation mOriginalAllocation = null;
51 private volatile Allocation mFiltersOnlyOriginalAllocation = null;
53 protected volatile Allocation mInPixelsAllocation;
54 protected volatile Allocation mOutPixelsAllocation;
55 private volatile int mWidth = 0;
56 private volatile int mHeight = 0;
58 private volatile float mPreviewScaleFactor = 1.0f;
59 private volatile float mHighResPreviewScaleFactor = 1.0f;
60 private volatile String mName = "";
62 public CachingPipeline(FiltersManager filtersManager, String name) {
63 mFiltersManager = filtersManager;
67 public static synchronized RenderScript getRenderScriptContext() {
71 public static synchronized void createRenderscriptContext(Context context) {
73 Log.w(LOGTAG, "A prior RS context exists when calling setRenderScriptContext");
74 destroyRenderScriptContext();
76 sRS = RenderScript.create(context);
79 public static synchronized void destroyRenderScriptContext() {
87 mEnvironment.setStop(true);
90 public synchronized void reset() {
91 synchronized (CachingPipeline.class) {
92 if (getRenderScriptContext() == null) {
95 mOriginalBitmap = null; // just a reference to the bitmap in ImageLoader
96 if (mResizedOriginalBitmap != null) {
97 mResizedOriginalBitmap.recycle();
98 mResizedOriginalBitmap = null;
100 if (mOriginalAllocation != null) {
101 mOriginalAllocation.destroy();
102 mOriginalAllocation = null;
104 if (mFiltersOnlyOriginalAllocation != null) {
105 mFiltersOnlyOriginalAllocation.destroy();
106 mFiltersOnlyOriginalAllocation = null;
108 mPreviewScaleFactor = 1.0f;
109 mHighResPreviewScaleFactor = 1.0f;
111 destroyPixelAllocations();
115 public Resources getResources() {
116 return sRS.getApplicationContext().getResources();
119 private synchronized void destroyPixelAllocations() {
121 Log.v(LOGTAG, "destroyPixelAllocations in " + getName());
123 if (mInPixelsAllocation != null) {
124 mInPixelsAllocation.destroy();
125 mInPixelsAllocation = null;
127 if (mOutPixelsAllocation != null) {
128 mOutPixelsAllocation.destroy();
129 mOutPixelsAllocation = null;
135 private String getType(RenderingRequest request) {
136 if (request.getType() == RenderingRequest.ICON_RENDERING) {
137 return "ICON_RENDERING";
139 if (request.getType() == RenderingRequest.FILTERS_RENDERING) {
140 return "FILTERS_RENDERING";
142 if (request.getType() == RenderingRequest.FULL_RENDERING) {
143 return "FULL_RENDERING";
145 if (request.getType() == RenderingRequest.GEOMETRY_RENDERING) {
146 return "GEOMETRY_RENDERING";
148 if (request.getType() == RenderingRequest.PARTIAL_RENDERING) {
149 return "PARTIAL_RENDERING";
151 if (request.getType() == RenderingRequest.HIGHRES_RENDERING) {
152 return "HIGHRES_RENDERING";
154 return "UNKNOWN TYPE!";
157 private void setupEnvironment(ImagePreset preset, boolean highResPreview) {
158 mEnvironment.setPipeline(this);
159 mEnvironment.setFiltersManager(mFiltersManager);
160 mEnvironment.setBitmapCache(MasterImage.getImage().getBitmapCache());
161 if (highResPreview) {
162 mEnvironment.setScaleFactor(mHighResPreviewScaleFactor);
164 mEnvironment.setScaleFactor(mPreviewScaleFactor);
166 mEnvironment.setQuality(FilterEnvironment.QUALITY_PREVIEW);
167 mEnvironment.setImagePreset(preset);
168 mEnvironment.setStop(false);
171 public void setOriginal(Bitmap bitmap) {
172 mOriginalBitmap = bitmap;
173 Log.v(LOGTAG,"setOriginal, size " + bitmap.getWidth() + " x " + bitmap.getHeight());
174 ImagePreset preset = MasterImage.getImage().getPreset();
175 setupEnvironment(preset, false);
176 updateOriginalAllocation(preset);
179 private synchronized boolean updateOriginalAllocation(ImagePreset preset) {
180 Bitmap originalBitmap = mOriginalBitmap;
182 if (originalBitmap == null) {
186 RenderScript RS = getRenderScriptContext();
188 Allocation filtersOnlyOriginalAllocation = mFiltersOnlyOriginalAllocation;
189 mFiltersOnlyOriginalAllocation = Allocation.createFromBitmap(RS, originalBitmap,
190 Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
191 if (filtersOnlyOriginalAllocation != null) {
192 filtersOnlyOriginalAllocation.destroy();
195 Allocation originalAllocation = mOriginalAllocation;
196 mResizedOriginalBitmap = preset.applyGeometry(originalBitmap, mEnvironment);
197 mOriginalAllocation = Allocation.createFromBitmap(RS, mResizedOriginalBitmap,
198 Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
199 if (originalAllocation != null) {
200 originalAllocation.destroy();
206 public void renderHighres(RenderingRequest request) {
207 synchronized (CachingPipeline.class) {
208 if (getRenderScriptContext() == null) {
211 ImagePreset preset = request.getImagePreset();
212 setupEnvironment(preset, false);
213 Bitmap bitmap = MasterImage.getImage().getOriginalBitmapHighres();
214 if (bitmap == null) {
217 bitmap = mEnvironment.getBitmapCopy(bitmap);
218 bitmap = preset.applyGeometry(bitmap, mEnvironment);
220 mEnvironment.setQuality(FilterEnvironment.QUALITY_PREVIEW);
221 Bitmap bmp = preset.apply(bitmap, mEnvironment);
222 if (!mEnvironment.needsStop()) {
223 request.setBitmap(bmp);
225 mEnvironment.cache(bmp);
227 mFiltersManager.freeFilterResources(preset);
231 public void renderGeometry(RenderingRequest request) {
232 synchronized (CachingPipeline.class) {
233 if (getRenderScriptContext() == null) {
236 ImagePreset preset = request.getImagePreset();
237 setupEnvironment(preset, false);
238 Bitmap bitmap = MasterImage.getImage().getOriginalBitmapHighres();
239 if (bitmap == null) {
242 bitmap = mEnvironment.getBitmapCopy(bitmap);
243 bitmap = preset.applyGeometry(bitmap, mEnvironment);
244 if (!mEnvironment.needsStop()) {
245 request.setBitmap(bitmap);
247 mEnvironment.cache(bitmap);
249 mFiltersManager.freeFilterResources(preset);
253 public void renderFilters(RenderingRequest request) {
254 synchronized (CachingPipeline.class) {
255 if (getRenderScriptContext() == null) {
258 ImagePreset preset = request.getImagePreset();
259 setupEnvironment(preset, false);
260 Bitmap bitmap = MasterImage.getImage().getOriginalBitmapHighres();
261 if (bitmap == null) {
264 bitmap = mEnvironment.getBitmapCopy(bitmap);
265 bitmap = preset.apply(bitmap, mEnvironment);
266 if (!mEnvironment.needsStop()) {
267 request.setBitmap(bitmap);
269 mEnvironment.cache(bitmap);
271 mFiltersManager.freeFilterResources(preset);
275 public synchronized void render(RenderingRequest request) {
276 // TODO: cleanup/remove GEOMETRY / FILTERS paths
277 synchronized (CachingPipeline.class) {
278 if (getRenderScriptContext() == null) {
281 if (((request.getType() != RenderingRequest.PARTIAL_RENDERING)
282 && request.getBitmap() == null)
283 || request.getImagePreset() == null) {
288 Log.v(LOGTAG, "render image of type " + getType(request));
291 Bitmap bitmap = request.getBitmap();
292 ImagePreset preset = request.getImagePreset();
293 setupEnvironment(preset, true);
294 mFiltersManager.freeFilterResources(preset);
296 if (request.getType() == RenderingRequest.PARTIAL_RENDERING) {
297 MasterImage master = MasterImage.getImage();
298 bitmap = ImageLoader.getScaleOneImageForPreset(master.getActivity(),
300 master.getUri(), request.getBounds(),
301 request.getDestination());
302 if (bitmap == null) {
303 Log.w(LOGTAG, "could not get bitmap for: " + getType(request));
308 if (request.getType() == RenderingRequest.FULL_RENDERING
309 || request.getType() == RenderingRequest.GEOMETRY_RENDERING
310 || request.getType() == RenderingRequest.FILTERS_RENDERING) {
311 updateOriginalAllocation(preset);
315 Log.v(LOGTAG, "after update, req bitmap (" + bitmap.getWidth() + "x" + bitmap.getHeight()
316 + " ? resizeOriginal (" + mResizedOriginalBitmap.getWidth() + "x"
317 + mResizedOriginalBitmap.getHeight());
320 if (request.getType() == RenderingRequest.FULL_RENDERING
321 || request.getType() == RenderingRequest.GEOMETRY_RENDERING) {
322 mOriginalAllocation.copyTo(bitmap);
323 } else if (request.getType() == RenderingRequest.FILTERS_RENDERING) {
324 mFiltersOnlyOriginalAllocation.copyTo(bitmap);
327 if (request.getType() == RenderingRequest.FULL_RENDERING
328 || request.getType() == RenderingRequest.FILTERS_RENDERING
329 || request.getType() == RenderingRequest.ICON_RENDERING
330 || request.getType() == RenderingRequest.PARTIAL_RENDERING
331 || request.getType() == RenderingRequest.STYLE_ICON_RENDERING) {
333 if (request.getType() == RenderingRequest.ICON_RENDERING) {
334 mEnvironment.setQuality(FilterEnvironment.QUALITY_ICON);
336 mEnvironment.setQuality(FilterEnvironment.QUALITY_PREVIEW);
339 Bitmap bmp = preset.apply(bitmap, mEnvironment);
340 if (!mEnvironment.needsStop()) {
341 request.setBitmap(bmp);
343 mFiltersManager.freeFilterResources(preset);
348 public synchronized void renderImage(ImagePreset preset, Allocation in, Allocation out) {
349 synchronized (CachingPipeline.class) {
350 if (getRenderScriptContext() == null) {
353 setupEnvironment(preset, false);
354 mFiltersManager.freeFilterResources(preset);
355 preset.applyFilters(-1, -1, in, out, mEnvironment);
356 boolean copyOut = false;
357 if (preset.nbFilters() > 0) {
360 preset.applyBorder(in, out, copyOut, mEnvironment);
364 public synchronized Bitmap renderFinalImage(Bitmap bitmap, ImagePreset preset) {
365 synchronized (CachingPipeline.class) {
366 if (getRenderScriptContext() == null) {
369 setupEnvironment(preset, false);
370 mEnvironment.setQuality(FilterEnvironment.QUALITY_FINAL);
371 mEnvironment.setScaleFactor(1.0f);
372 mFiltersManager.freeFilterResources(preset);
373 bitmap = preset.applyGeometry(bitmap, mEnvironment);
374 bitmap = preset.apply(bitmap, mEnvironment);
379 public Bitmap renderGeometryIcon(Bitmap bitmap, ImagePreset preset) {
380 return GeometryMathUtils.applyGeometryRepresentations(preset.getGeometryFilters(), bitmap);
383 public void compute(SharedBuffer buffer, ImagePreset preset, int type) {
384 if (getRenderScriptContext() == null) {
387 setupEnvironment(preset, false);
388 Vector<FilterRepresentation> filters = preset.getFilters();
389 Bitmap result = mCachedProcessing.process(mOriginalBitmap, filters, mEnvironment);
390 buffer.setProducer(result);
391 mEnvironment.cache(result);
394 public synchronized void computeOld(SharedBuffer buffer, ImagePreset preset, int type) {
395 synchronized (CachingPipeline.class) {
396 if (getRenderScriptContext() == null) {
400 Log.v(LOGTAG, "compute preset " + preset);
401 preset.showFilters();
404 String thread = Thread.currentThread().getName();
405 long time = System.currentTimeMillis();
406 setupEnvironment(preset, false);
407 mFiltersManager.freeFilterResources(preset);
409 Bitmap resizedOriginalBitmap = mResizedOriginalBitmap;
410 if (updateOriginalAllocation(preset) || buffer.getProducer() == null) {
411 resizedOriginalBitmap = mResizedOriginalBitmap;
412 buffer.setProducer(resizedOriginalBitmap);
413 mEnvironment.cache(buffer.getProducer());
416 Bitmap bitmap = buffer.getProducer().getBitmap();
417 long time2 = System.currentTimeMillis();
419 if (bitmap == null || (bitmap.getWidth() != resizedOriginalBitmap.getWidth())
420 || (bitmap.getHeight() != resizedOriginalBitmap.getHeight())) {
421 mEnvironment.cache(buffer.getProducer());
422 buffer.setProducer(resizedOriginalBitmap);
423 bitmap = buffer.getProducer().getBitmap();
425 mOriginalAllocation.copyTo(bitmap);
427 Bitmap tmpbitmap = preset.apply(bitmap, mEnvironment);
428 if (tmpbitmap != bitmap) {
429 mEnvironment.cache(buffer.getProducer());
430 buffer.setProducer(tmpbitmap);
433 mFiltersManager.freeFilterResources(preset);
435 time = System.currentTimeMillis() - time;
436 time2 = System.currentTimeMillis() - time2;
438 Log.v(LOGTAG, "Applying type " + type + " filters to bitmap "
439 + bitmap + " (" + bitmap.getWidth() + " x " + bitmap.getHeight()
440 + ") took " + time + " ms, " + time2 + " ms for the filter, on thread " + thread);
445 public boolean needsRepaint() {
446 SharedBuffer buffer = MasterImage.getImage().getPreviewBuffer();
447 return buffer.checkRepaintNeeded();
450 public void setPreviewScaleFactor(float previewScaleFactor) {
451 mPreviewScaleFactor = previewScaleFactor;
454 public void setHighResPreviewScaleFactor(float highResPreviewScaleFactor) {
455 mHighResPreviewScaleFactor = highResPreviewScaleFactor;
458 public synchronized boolean isInitialized() {
459 return getRenderScriptContext() != null && mOriginalBitmap != null;
462 public boolean prepareRenderscriptAllocations(Bitmap bitmap) {
463 RenderScript RS = getRenderScriptContext();
464 boolean needsUpdate = false;
465 if (mOutPixelsAllocation == null || mInPixelsAllocation == null ||
466 bitmap.getWidth() != mWidth || bitmap.getHeight() != mHeight) {
467 destroyPixelAllocations();
468 Bitmap bitmapBuffer = bitmap;
469 if (bitmap.getConfig() == null || bitmap.getConfig() != BITMAP_CONFIG) {
470 bitmapBuffer = bitmap.copy(BITMAP_CONFIG, true);
472 mOutPixelsAllocation = Allocation.createFromBitmap(RS, bitmapBuffer,
473 Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
474 mInPixelsAllocation = Allocation.createTyped(RS,
475 mOutPixelsAllocation.getType());
479 mInPixelsAllocation.copyFrom(bitmap);
481 if (bitmap.getWidth() != mWidth
482 || bitmap.getHeight() != mHeight) {
483 mWidth = bitmap.getWidth();
484 mHeight = bitmap.getHeight();
488 Log.v(LOGTAG, "prepareRenderscriptAllocations: " + needsUpdate + " in " + getName());
493 public synchronized Allocation getInPixelsAllocation() {
494 return mInPixelsAllocation;
497 public synchronized Allocation getOutPixelsAllocation() {
498 return mOutPixelsAllocation;
501 public String getName() {
505 public RenderScript getRSContext() {
506 return CachingPipeline.getRenderScriptContext();