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.cache;
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;
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;
33 public class CachingPipeline {
34 private static final String LOGTAG = "CachingPipeline";
35 private boolean DEBUG = false;
37 private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
39 private static volatile RenderScript sRS = null;
40 private static volatile Resources sResources = null;
42 private FiltersManager mFiltersManager = null;
43 private volatile Bitmap mOriginalBitmap = null;
44 private volatile Bitmap mResizedOriginalBitmap = null;
46 private FilterEnvironment mEnvironment = new FilterEnvironment();
48 private volatile Allocation mOriginalAllocation = null;
49 private volatile Allocation mFiltersOnlyOriginalAllocation = null;
51 protected volatile Allocation mInPixelsAllocation;
52 protected volatile Allocation mOutPixelsAllocation;
53 private volatile int mWidth = 0;
54 private volatile int mHeight = 0;
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 = "";
61 private ImageFilterGeometry mGeometry = null;
63 public CachingPipeline(FiltersManager filtersManager, String name) {
64 mFiltersManager = filtersManager;
68 public static synchronized Resources getResources() {
72 public static synchronized void setResources(Resources resources) {
73 sResources = resources;
76 public static synchronized RenderScript getRenderScriptContext() {
80 public static synchronized void setRenderScriptContext(RenderScript RS) {
84 public static synchronized void createRenderscriptContext(Activity context) {
86 Log.w(LOGTAG, "A prior RS context exists when calling setRenderScriptContext");
87 destroyRenderScriptContext();
89 sRS = RenderScript.create(context);
90 sResources = context.getResources();
93 public static synchronized void destroyRenderScriptContext() {
100 mEnvironment.setStop(true);
103 public synchronized void reset() {
104 synchronized (CachingPipeline.class) {
105 if (getRenderScriptContext() == null) {
108 mOriginalBitmap = null; // just a reference to the bitmap in ImageLoader
109 if (mResizedOriginalBitmap != null) {
110 mResizedOriginalBitmap.recycle();
111 mResizedOriginalBitmap = null;
113 if (mOriginalAllocation != null) {
114 mOriginalAllocation.destroy();
115 mOriginalAllocation = null;
117 if (mFiltersOnlyOriginalAllocation != null) {
118 mFiltersOnlyOriginalAllocation.destroy();
119 mFiltersOnlyOriginalAllocation = null;
121 mPreviousGeometry = null;
122 mPreviewScaleFactor = 1.0f;
123 mHighResPreviewScaleFactor = 1.0f;
125 destroyPixelAllocations();
129 private synchronized void destroyPixelAllocations() {
131 Log.v(LOGTAG, "destroyPixelAllocations in " + getName());
133 if (mInPixelsAllocation != null) {
134 mInPixelsAllocation.destroy();
135 mInPixelsAllocation = null;
137 if (mOutPixelsAllocation != null) {
138 mOutPixelsAllocation.destroy();
139 mOutPixelsAllocation = null;
145 private String getType(RenderingRequest request) {
146 if (request.getType() == RenderingRequest.ICON_RENDERING) {
147 return "ICON_RENDERING";
149 if (request.getType() == RenderingRequest.FILTERS_RENDERING) {
150 return "FILTERS_RENDERING";
152 if (request.getType() == RenderingRequest.FULL_RENDERING) {
153 return "FULL_RENDERING";
155 if (request.getType() == RenderingRequest.GEOMETRY_RENDERING) {
156 return "GEOMETRY_RENDERING";
158 if (request.getType() == RenderingRequest.PARTIAL_RENDERING) {
159 return "PARTIAL_RENDERING";
161 if (request.getType() == RenderingRequest.HIGHRES_RENDERING) {
162 return "HIGHRES_RENDERING";
164 return "UNKNOWN TYPE!";
167 private void setupEnvironment(ImagePreset preset, boolean highResPreview) {
168 mEnvironment.setCachingPipeline(this);
169 mEnvironment.setFiltersManager(mFiltersManager);
170 if (highResPreview) {
171 mEnvironment.setScaleFactor(mHighResPreviewScaleFactor);
173 mEnvironment.setScaleFactor(mPreviewScaleFactor);
175 mEnvironment.setQuality(ImagePreset.QUALITY_PREVIEW);
176 mEnvironment.setImagePreset(preset);
177 mEnvironment.setStop(false);
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);
188 private synchronized boolean updateOriginalAllocation(ImagePreset preset) {
189 Bitmap originalBitmap = mOriginalBitmap;
191 if (originalBitmap == null) {
195 GeometryMetadata geometry = preset.getGeometry();
196 if (mPreviousGeometry != null && geometry.equals(mPreviousGeometry)) {
201 Log.v(LOGTAG, "geometry has changed");
204 RenderScript RS = getRenderScriptContext();
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();
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();
221 mPreviousGeometry = new GeometryMetadata(geometry);
225 public synchronized void render(RenderingRequest request) {
226 synchronized (CachingPipeline.class) {
227 if (getRenderScriptContext() == null) {
230 if (((request.getType() != RenderingRequest.PARTIAL_RENDERING
231 && request.getType() != RenderingRequest.HIGHRES_RENDERING)
232 && request.getBitmap() == null)
233 || request.getImagePreset() == null) {
238 Log.v(LOGTAG, "render image of type " + getType(request));
241 Bitmap bitmap = request.getBitmap();
242 ImagePreset preset = request.getImagePreset();
243 setupEnvironment(preset,
244 request.getType() != RenderingRequest.HIGHRES_RENDERING);
245 mFiltersManager.freeFilterResources(preset);
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));
253 bitmap = loader.getScaleOneImageForPreset(request.getBounds(),
254 request.getDestination());
255 if (bitmap == null) {
256 Log.w(LOGTAG, "could not get bitmap for: " + getType(request));
261 if (request.getType() == RenderingRequest.HIGHRES_RENDERING) {
262 ImageLoader loader = MasterImage.getImage().getImageLoader();
263 bitmap = loader.getOriginalBitmapHighres();
264 bitmap = preset.applyGeometry(bitmap, mEnvironment);
267 if (request.getType() == RenderingRequest.FULL_RENDERING
268 || request.getType() == RenderingRequest.GEOMETRY_RENDERING
269 || request.getType() == RenderingRequest.FILTERS_RENDERING) {
270 updateOriginalAllocation(preset);
274 Log.v(LOGTAG, "after update, req bitmap (" + bitmap.getWidth() + "x" + bitmap.getHeight()
275 + " ? resizeOriginal (" + mResizedOriginalBitmap.getWidth() + "x"
276 + mResizedOriginalBitmap.getHeight());
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);
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) {
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);
298 mEnvironment.setQuality(ImagePreset.QUALITY_PREVIEW);
301 Bitmap bmp = preset.apply(bitmap, mEnvironment);
302 if (!mEnvironment.needsStop()) {
303 request.setBitmap(bmp);
305 mFiltersManager.freeFilterResources(preset);
310 public synchronized void renderImage(ImagePreset preset, Allocation in, Allocation out) {
311 synchronized (CachingPipeline.class) {
312 if (getRenderScriptContext() == null) {
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) {
322 preset.applyBorder(in, out, copyOut, mEnvironment);
326 public synchronized Bitmap renderFinalImage(Bitmap bitmap, ImagePreset preset) {
327 synchronized (CachingPipeline.class) {
328 if (getRenderScriptContext() == null) {
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);
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();
347 mGeometry.useRepresentation(preset.getGeometry());
348 return mGeometry.apply(bitmap, mPreviewScaleFactor,
349 ImagePreset.QUALITY_PREVIEW);
352 public synchronized void compute(TripleBufferBitmap buffer, ImagePreset preset, int type) {
353 synchronized (CachingPipeline.class) {
354 if (getRenderScriptContext() == null) {
358 Log.v(LOGTAG, "compute preset " + preset);
359 preset.showFilters();
362 String thread = Thread.currentThread().getName();
363 long time = System.currentTimeMillis();
364 setupEnvironment(preset, false);
365 mFiltersManager.freeFilterResources(preset);
367 Bitmap resizedOriginalBitmap = mResizedOriginalBitmap;
368 if (updateOriginalAllocation(preset)) {
369 resizedOriginalBitmap = mResizedOriginalBitmap;
370 mEnvironment.cache(buffer.getProducer());
371 buffer.updateProducerBitmap(resizedOriginalBitmap);
373 Bitmap bitmap = buffer.getProducer();
374 long time2 = System.currentTimeMillis();
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();
382 mOriginalAllocation.copyTo(bitmap);
384 Bitmap tmpbitmap = preset.apply(bitmap, mEnvironment);
385 if (tmpbitmap != bitmap) {
386 mEnvironment.cache(buffer.getProducer());
387 buffer.setProducer(tmpbitmap);
390 mFiltersManager.freeFilterResources(preset);
392 time = System.currentTimeMillis() - time;
393 time2 = System.currentTimeMillis() - time2;
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);
402 public boolean needsRepaint() {
403 TripleBufferBitmap buffer = MasterImage.getImage().getDoubleBuffer();
404 return buffer.checkRepaintNeeded();
407 public void setPreviewScaleFactor(float previewScaleFactor) {
408 mPreviewScaleFactor = previewScaleFactor;
411 public void setHighResPreviewScaleFactor(float highResPreviewScaleFactor) {
412 mHighResPreviewScaleFactor = highResPreviewScaleFactor;
415 public synchronized boolean isInitialized() {
416 return getRenderScriptContext() != null && mOriginalBitmap != null;
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);
429 mOutPixelsAllocation = Allocation.createFromBitmap(RS, bitmapBuffer,
430 Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
431 mInPixelsAllocation = Allocation.createTyped(RS,
432 mOutPixelsAllocation.getType());
436 mInPixelsAllocation.copyFrom(bitmap);
438 if (bitmap.getWidth() != mWidth
439 || bitmap.getHeight() != mHeight) {
440 mWidth = bitmap.getWidth();
441 mHeight = bitmap.getHeight();
445 Log.v(LOGTAG, "prepareRenderscriptAllocations: " + needsUpdate + " in " + getName());
450 public synchronized Allocation getInPixelsAllocation() {
451 return mInPixelsAllocation;
454 public synchronized Allocation getOutPixelsAllocation() {
455 return mOutPixelsAllocation;
458 public String getName() {