From 09ec2d5a01ccfce82b58c77959ec1464ec670855 Mon Sep 17 00:00:00 2001 From: nicolasroard Date: Wed, 20 Mar 2013 08:41:34 -0700 Subject: Refactor the pipeline - add a CachingPipeline class - FilteringPipeline only deals with communication - fix large critical sections performance issues - improves stability bug:8418537 Change-Id: Id18edf71b2e2aec19a8b25fcce711c4acbb1a724 --- .../filtershow/cache/CachingPipeline.java | 247 +++++++++++++++++++++ .../filtershow/cache/FilteringPipeline.java | 230 +++---------------- .../filtershow/imageshow/ImageVignette.java | 7 +- 3 files changed, 281 insertions(+), 203 deletions(-) create mode 100644 src/com/android/gallery3d/filtershow/cache/CachingPipeline.java (limited to 'src') diff --git a/src/com/android/gallery3d/filtershow/cache/CachingPipeline.java b/src/com/android/gallery3d/filtershow/cache/CachingPipeline.java new file mode 100644 index 000000000..9d4da0214 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/cache/CachingPipeline.java @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.gallery3d.filtershow.cache; + +import android.graphics.Bitmap; +import android.support.v8.renderscript.Allocation; +import android.support.v8.renderscript.RenderScript; +import android.util.Log; +import com.android.gallery3d.filtershow.filters.FiltersManager; +import com.android.gallery3d.filtershow.filters.ImageFilterRS; +import com.android.gallery3d.filtershow.imageshow.GeometryMetadata; +import com.android.gallery3d.filtershow.imageshow.MasterImage; +import com.android.gallery3d.filtershow.presets.ImagePreset; + +public class CachingPipeline { + private static final String LOGTAG = "CachingPipeline"; + private boolean DEBUG = false; + + private FiltersManager mFiltersManager = null; + private volatile Bitmap mOriginalBitmap = null; + private volatile Bitmap mResizedOriginalBitmap = null; + + private volatile Allocation mOriginalAllocation = null; + private volatile Allocation mFiltersOnlyOriginalAllocation = null; + + private volatile GeometryMetadata mPreviousGeometry = null; + private volatile float mPreviewScaleFactor = 1.0f; + + public CachingPipeline(FiltersManager filtersManager) { + mFiltersManager = filtersManager; + } + + public synchronized void reset() { + mOriginalBitmap = null; // just a reference to the bitmap in ImageLoader + if (mResizedOriginalBitmap != null) { + mResizedOriginalBitmap.recycle(); + mResizedOriginalBitmap = null; + } + if (mOriginalAllocation != null) { + mOriginalAllocation.destroy(); + mOriginalAllocation = null; + } + if (mFiltersOnlyOriginalAllocation != null) { + mFiltersOnlyOriginalAllocation.destroy(); + mFiltersOnlyOriginalAllocation = null; + } + mPreviousGeometry = null; + mPreviewScaleFactor = 1.0f; + } + + private String getType(RenderingRequest request) { + if (request.getType() == RenderingRequest.ICON_RENDERING) { + return "ICON_RENDERING"; + } + if (request.getType() == RenderingRequest.FILTERS_RENDERING) { + return "FILTERS_RENDERING"; + } + if (request.getType() == RenderingRequest.FULL_RENDERING) { + return "FULL_RENDERING"; + } + if (request.getType() == RenderingRequest.GEOMETRY_RENDERING) { + return "GEOMETRY_RENDERING"; + } + if (request.getType() == RenderingRequest.PARTIAL_RENDERING) { + return "PARTIAL_RENDERING"; + } + return "UNKNOWN TYPE!"; + } + + private void setPresetParameters(ImagePreset preset) { + preset.setScaleFactor(mPreviewScaleFactor); + preset.setQuality(ImagePreset.QUALITY_PREVIEW); + preset.setupEnvironment(mFiltersManager); + } + + public void setOriginal(Bitmap bitmap) { + mOriginalBitmap = bitmap; + Log.v(LOGTAG,"setOriginal, size " + bitmap.getWidth() + " x " + bitmap.getHeight()); + ImagePreset preset = MasterImage.getImage().getPreset(); + preset.setupEnvironment(mFiltersManager); + updateOriginalAllocation(preset); + } + + private synchronized boolean updateOriginalAllocation(ImagePreset preset) { + Bitmap originalBitmap = mOriginalBitmap; + + if (originalBitmap == null) { + return false; + } + + GeometryMetadata geometry = preset.getGeometry(); + if (mPreviousGeometry != null && geometry.equals(mPreviousGeometry)) { + return false; + } + + if (DEBUG) { + Log.v(LOGTAG, "geometry has changed"); + } + + RenderScript RS = ImageFilterRS.getRenderScriptContext(); + + Allocation filtersOnlyOriginalAllocation = mFiltersOnlyOriginalAllocation; + mFiltersOnlyOriginalAllocation = Allocation.createFromBitmap(RS, originalBitmap, + Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT); + if (filtersOnlyOriginalAllocation != null) { + filtersOnlyOriginalAllocation.destroy(); + } + + Allocation originalAllocation = mOriginalAllocation; + mResizedOriginalBitmap = preset.applyGeometry(originalBitmap); + mOriginalAllocation = Allocation.createFromBitmap(RS, mResizedOriginalBitmap, + Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT); + if (originalAllocation != null) { + originalAllocation.destroy(); + } + + mPreviousGeometry = new GeometryMetadata(geometry); + return true; + } + + public synchronized void render(RenderingRequest request) { + if ((request.getType() != RenderingRequest.PARTIAL_RENDERING + && request.getBitmap() == null) + || request.getImagePreset() == null) { + return; + } + + if (DEBUG) { + Log.v(LOGTAG, "render image of type " + getType(request)); + } + + Bitmap bitmap = request.getBitmap(); + ImagePreset preset = request.getImagePreset(); + setPresetParameters(preset); + mFiltersManager.freeFilterResources(preset); + + if (request.getType() == RenderingRequest.PARTIAL_RENDERING) { + ImageLoader loader = MasterImage.getImage().getImageLoader(); + if (loader == null) { + Log.w(LOGTAG, "loader not yet setup, cannot handle: " + getType(request)); + return; + } + bitmap = loader.getScaleOneImageForPreset(null, preset, + request.getBounds(), request.getDestination(), false); + if (bitmap == null) { + Log.w(LOGTAG, "could not get bitmap for: " + getType(request)); + return; + } + } + + if (request.getType() == RenderingRequest.FULL_RENDERING + || request.getType() == RenderingRequest.GEOMETRY_RENDERING + || request.getType() == RenderingRequest.FILTERS_RENDERING) { + updateOriginalAllocation(preset); + } + + if (DEBUG) { + Log.v(LOGTAG, "after update, req bitmap (" + bitmap.getWidth() + "x" + bitmap.getHeight() + +" ? resizeOriginal (" + mResizedOriginalBitmap.getWidth() + "x" + + mResizedOriginalBitmap.getHeight()); + } + + if (request.getType() == RenderingRequest.FULL_RENDERING + || request.getType() == RenderingRequest.GEOMETRY_RENDERING) { + mOriginalAllocation.copyTo(bitmap); + } else if (request.getType() == RenderingRequest.FILTERS_RENDERING) { + mFiltersOnlyOriginalAllocation.copyTo(bitmap); + } + + if (request.getType() == RenderingRequest.FULL_RENDERING + || request.getType() == RenderingRequest.FILTERS_RENDERING + || request.getType() == RenderingRequest.ICON_RENDERING + || request.getType() == RenderingRequest.PARTIAL_RENDERING) { + Bitmap bmp = preset.apply(bitmap); + request.setBitmap(bmp); + mFiltersManager.freeFilterResources(preset); + } + + } + + public synchronized void compute(TripleBufferBitmap buffer, ImagePreset preset, int type) { + if (DEBUG) { + Log.v(LOGTAG, "compute preset " + preset); + preset.showFilters(); + } + + String thread = Thread.currentThread().getName(); + long time = System.currentTimeMillis(); + setPresetParameters(preset); + mFiltersManager.freeFilterResources(preset); + + Bitmap resizedOriginalBitmap = mResizedOriginalBitmap; + if (updateOriginalAllocation(preset)) { + resizedOriginalBitmap = mResizedOriginalBitmap; + buffer.updateBitmaps(resizedOriginalBitmap); + } + Bitmap bitmap = buffer.getProducer(); + long time2 = System.currentTimeMillis(); + + if (bitmap == null || (bitmap.getWidth() != resizedOriginalBitmap.getWidth()) + || (bitmap.getHeight() != resizedOriginalBitmap.getHeight())) { + buffer.updateBitmaps(resizedOriginalBitmap); + bitmap = buffer.getProducer(); + } + mOriginalAllocation.copyTo(bitmap); + + bitmap = preset.apply(bitmap); + + mFiltersManager.freeFilterResources(preset); + + time = System.currentTimeMillis() - time; + time2 = System.currentTimeMillis() - time2; + if (DEBUG) { + Log.v(LOGTAG, "Applying type " + type + " filters to bitmap " + + bitmap + " (" + bitmap.getWidth() + " x " + bitmap.getHeight() + + ") took " + time + " ms, " + time2 + " ms for the filter, on thread " + thread); + } + } + + public boolean needsRepaint() { + TripleBufferBitmap buffer = MasterImage.getImage().getDoubleBuffer(); + return buffer.checkRepaintNeeded(); + } + + + public void setPreviewScaleFactor(float previewScaleFactor) { + mPreviewScaleFactor = previewScaleFactor; + } + + public synchronized boolean isInitialized() { + return mOriginalBitmap != null; + } +} diff --git a/src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java b/src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java index c3d049fbd..20af215e4 100644 --- a/src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java +++ b/src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java @@ -32,14 +32,14 @@ public class FilteringPipeline implements Handler.Callback { private static volatile FilteringPipeline sPipeline = null; private static final String LOGTAG = "FilteringPipeline"; - private volatile GeometryMetadata mPreviousGeometry = null; - private volatile float mPreviewScaleFactor = 1.0f; - private volatile boolean mPipelineIsOn = false; + private boolean DEBUG = false; - private volatile Bitmap mOriginalBitmap = null; - private volatile Bitmap mResizedOriginalBitmap = null; + private static long HIRES_DELAY = 100; // in ms - private boolean DEBUG = false; + private volatile boolean mPipelineIsOn = false; + + private CachingPipeline mAccessoryPipeline = null; + private CachingPipeline mPreviewPipeline = null; private HandlerThread mHandlerThread = null; private final static int NEW_PRESET = 0; @@ -82,7 +82,7 @@ public class FilteringPipeline implements Handler.Callback { case COMPUTE_PRESET: { ImagePreset preset = (ImagePreset) msg.obj; TripleBufferBitmap buffer = MasterImage.getImage().getDoubleBuffer(); - compute(buffer, preset, COMPUTE_PRESET); + mPreviewPipeline.compute(buffer, preset, COMPUTE_PRESET); buffer.swapProducer(); Message uimsg = mUIHandler.obtainMessage(NEW_PRESET); mUIHandler.sendMessage(uimsg); @@ -96,7 +96,7 @@ public class FilteringPipeline implements Handler.Callback { } } RenderingRequest request = (RenderingRequest) msg.obj; - render(request); + mAccessoryPipeline.render(request); Message uimsg = mUIHandler.obtainMessage(NEW_RENDERING_REQUEST); uimsg.obj = request; mUIHandler.sendMessage(uimsg); @@ -106,18 +106,13 @@ public class FilteringPipeline implements Handler.Callback { return false; } - private static float RESIZE_FACTOR = 0.8f; - private static float MAX_PROCESS_TIME = 100; // in ms - private static long HIRES_DELAY = 100; // in ms - - private volatile Allocation mOriginalAllocation = null; - private volatile Allocation mFiltersOnlyOriginalAllocation = null; - private FilteringPipeline() { mHandlerThread = new HandlerThread("FilteringPipeline", Process.THREAD_PRIORITY_FOREGROUND); mHandlerThread.start(); mProcessingHandler = new Handler(mHandlerThread.getLooper(), this); + mAccessoryPipeline = new CachingPipeline(FiltersManager.getManager()); + mPreviewPipeline = new CachingPipeline(FiltersManager.getPreviewManager()); } public synchronized static FilteringPipeline getPipeline() { @@ -127,61 +122,17 @@ public class FilteringPipeline implements Handler.Callback { return sPipeline; } - public synchronized void setOriginal(Bitmap bitmap) { - mOriginalBitmap = bitmap; - Log.v(LOGTAG,"setOriginal, size " + bitmap.getWidth() + " x " + bitmap.getHeight()); - ImagePreset preset = MasterImage.getImage().getPreset(); - preset.setupEnvironment(); - updateOriginalAllocation(preset); - updatePreviewBuffer(); - } - - public synchronized boolean updateOriginalAllocation(ImagePreset preset) { - if (mOriginalBitmap == null) { - return false; - } - /* - //FIXME: turn back on the on-the-fly resize. - int w = (int) (mOriginalBitmap.getWidth() * mResizeFactor); - int h = (int) (mOriginalBitmap.getHeight() * mResizeFactor); - if (!needsGeometryRepaint() && mResizedOriginalBitmap != null && w == mResizedOriginalBitmap.getWidth()) { - return false; - } - mResizedOriginalBitmap = Bitmap.createScaledBitmap(mOriginalBitmap, w, h, true); - */ - - GeometryMetadata geometry = preset.getGeometry(); - if (mPreviousGeometry != null && geometry.equals(mPreviousGeometry)) { - return false; - } - - if (DEBUG) { - Log.v(LOGTAG, "geometry has changed"); - } - - RenderScript RS = ImageFilterRS.getRenderScriptContext(); - if (mFiltersOnlyOriginalAllocation != null) { - mFiltersOnlyOriginalAllocation.destroy(); - mFiltersOnlyOriginalAllocation = null; - } - mFiltersOnlyOriginalAllocation = Allocation.createFromBitmap(RS, mOriginalBitmap, - Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT); - if (mOriginalAllocation != null) { - mOriginalAllocation.destroy(); - mOriginalAllocation = null; + public void setOriginal(Bitmap bitmap) { + if (mPipelineIsOn) { + Log.e(LOGTAG, "setOriginal called after pipeline initialization!"); + return; } - mResizedOriginalBitmap = preset.applyGeometry(mOriginalBitmap); - mOriginalAllocation = Allocation.createFromBitmap(RS, mResizedOriginalBitmap, - Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT); - - mPreviousGeometry = new GeometryMetadata(geometry); - return true; + Log.v(LOGTAG,"setOriginal, size " + bitmap.getWidth() + " x " + bitmap.getHeight()); + mAccessoryPipeline.setOriginal(bitmap); + mPreviewPipeline.setOriginal(bitmap); } public void postRenderingRequest(RenderingRequest request) { - if (mOriginalAllocation == null) { - return; - } if (!mPipelineIsOn) { return; } @@ -198,15 +149,15 @@ public class FilteringPipeline implements Handler.Callback { } } - public synchronized void updatePreviewBuffer() { - if (mOriginalAllocation == null) { + public void updatePreviewBuffer() { + if (!mPipelineIsOn) { return; } mHasUnhandledPreviewRequest = true; if (mProcessingHandler.hasMessages(COMPUTE_PRESET)) { return; } - if (!needsRepaint()) { + if (!mPreviewPipeline.needsRepaint()) { return; } if (MasterImage.getImage().getPreset() == null) { @@ -218,147 +169,24 @@ public class FilteringPipeline implements Handler.Callback { mProcessingHandler.sendMessageAtFrontOfQueue(msg); } - private void setPresetParameters(ImagePreset preset) { - float scale = mPreviewScaleFactor; - preset.setScaleFactor(scale); - if (scale < 1.0f) { - preset.setQuality(ImagePreset.QUALITY_PREVIEW); - } else { - preset.setQuality(ImagePreset.QUALITY_PREVIEW); - } - } - - private String getType(RenderingRequest request) { - if (request.getType() == RenderingRequest.ICON_RENDERING) { - return "ICON_RENDERING"; - } - if (request.getType() == RenderingRequest.FILTERS_RENDERING) { - return "FILTERS_RENDERING"; - } - if (request.getType() == RenderingRequest.FULL_RENDERING) { - return "FULL_RENDERING"; - } - if (request.getType() == RenderingRequest.GEOMETRY_RENDERING) { - return "GEOMETRY_RENDERING"; - } - if (request.getType() == RenderingRequest.PARTIAL_RENDERING) { - return "PARTIAL_RENDERING"; - } - return "UNKNOWN TYPE!"; - } - - private synchronized void render(RenderingRequest request) { - if ((request.getType() != RenderingRequest.PARTIAL_RENDERING - && request.getBitmap() == null) - || request.getImagePreset() == null) { - return; - } - if (DEBUG) { - Log.v(LOGTAG, "render image of type " + getType(request)); - } - - Bitmap bitmap = request.getBitmap(); - ImagePreset preset = request.getImagePreset(); - setPresetParameters(preset); - preset.setupEnvironment(); - - if (request.getType() == RenderingRequest.PARTIAL_RENDERING) { - ImageLoader loader = MasterImage.getImage().getImageLoader(); - if (loader == null) { - Log.w(LOGTAG, "loader not yet setup, cannot handle: " + getType(request)); - return; - } - bitmap = loader.getScaleOneImageForPreset(null, preset, - request.getBounds(), request.getDestination(), false); - if (bitmap == null) { - Log.w(LOGTAG, "could not get bitmap for: " + getType(request)); - return; - } - } - - if (request.getType() != RenderingRequest.ICON_RENDERING - && request.getType() != RenderingRequest.PARTIAL_RENDERING) { - updateOriginalAllocation(preset); - } - if (DEBUG) { - Log.v(LOGTAG, "after update, req bitmap (" + bitmap.getWidth() + "x" + bitmap.getHeight() - +" ? resizeOriginal (" + mResizedOriginalBitmap.getWidth() + "x" - + mResizedOriginalBitmap.getHeight()); - } - if (request.getType() == RenderingRequest.FULL_RENDERING - || request.getType() == RenderingRequest.GEOMETRY_RENDERING) { - mOriginalAllocation.copyTo(bitmap); - } else if (request.getType() == RenderingRequest.FILTERS_RENDERING) { - mFiltersOnlyOriginalAllocation.copyTo(bitmap); - } - - if (request.getType() == RenderingRequest.FULL_RENDERING - || request.getType() == RenderingRequest.FILTERS_RENDERING - || request.getType() == RenderingRequest.ICON_RENDERING - || request.getType() == RenderingRequest.PARTIAL_RENDERING) { - Bitmap bmp = preset.apply(bitmap); - request.setBitmap(bmp); - - FiltersManager.getManager().freeFilterResources(preset); - } - - } - - private synchronized void compute(TripleBufferBitmap buffer, ImagePreset preset, int type) { - if (DEBUG) { - Log.v(LOGTAG, "compute preset " + preset); - preset.showFilters(); - } - - String thread = Thread.currentThread().getName(); - long time = System.currentTimeMillis(); - setPresetParameters(preset); - preset.setupEnvironment(FiltersManager.getPreviewManager()); - - if (updateOriginalAllocation(preset)) { - buffer.updateBitmaps(mResizedOriginalBitmap); - } - Bitmap bitmap = buffer.getProducer(); - long time2 = System.currentTimeMillis(); - - if (bitmap == null || (bitmap.getWidth() != mResizedOriginalBitmap.getWidth()) - || (bitmap.getHeight() != mResizedOriginalBitmap.getHeight())) { - buffer.updateBitmaps(mResizedOriginalBitmap); - bitmap = buffer.getProducer(); - } - mOriginalAllocation.copyTo(bitmap); - - bitmap = preset.apply(bitmap); - FiltersManager.getPreviewManager().freeFilterResources(preset); - - time = System.currentTimeMillis() - time; - time2 = System.currentTimeMillis() - time2; - if (DEBUG) { - Log.v(LOGTAG, "Applying type " + type + " filters to bitmap " - + bitmap + " (" + bitmap.getWidth() + " x " + bitmap.getHeight() - + ") took " + time + " ms, " + time2 + " ms for the filter, on thread " + thread); - } - } - - private synchronized boolean needsRepaint() { - TripleBufferBitmap buffer = MasterImage.getImage().getDoubleBuffer(); - return buffer.checkRepaintNeeded(); - } - public void setPreviewScaleFactor(float previewScaleFactor) { - mPreviewScaleFactor = previewScaleFactor; - } - - public float getPreviewScaleFactor() { - return mPreviewScaleFactor; + mAccessoryPipeline.setPreviewScaleFactor(previewScaleFactor); + mPreviewPipeline.setPreviewScaleFactor(previewScaleFactor); } public static synchronized void reset() { + sPipeline.mAccessoryPipeline.reset(); + sPipeline.mPreviewPipeline.reset(); sPipeline.mHandlerThread.quit(); sPipeline = null; } public void turnOnPipeline(boolean t) { mPipelineIsOn = t; + if (mPipelineIsOn) { + assert(mPreviewPipeline.isInitialized()); + assert(mAccessoryPipeline.isInitialized()); + updatePreviewBuffer(); + } } } diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageVignette.java b/src/com/android/gallery3d/filtershow/imageshow/ImageVignette.java index c55e5ae42..1149263df 100644 --- a/src/com/android/gallery3d/filtershow/imageshow/ImageVignette.java +++ b/src/com/android/gallery3d/filtershow/imageshow/ImageVignette.java @@ -77,18 +77,21 @@ public class ImageVignette extends ImageShow { mElipse.setScrToImageMatrix(getScreenToImageMatrix(true)); + boolean didComputeEllipses = false; switch (mask) { case (MotionEvent.ACTION_DOWN): mElipse.actionDown(x, y, mVignetteRep); break; case (MotionEvent.ACTION_UP): case (MotionEvent.ACTION_MOVE): - mElipse.actionMove(mActiveHandle, x, y, mVignetteRep); setRepresentation(mVignetteRep); + didComputeEllipses = true; break; } - computeEllipses(); + if (!didComputeEllipses) { + computeEllipses(); + } invalidate(); return true; } -- cgit v1.2.3