From f1f0d01da7742d46a546176081b441bdd23378f6 Mon Sep 17 00:00:00 2001 From: nicolasroard Date: Tue, 2 Jul 2013 11:00:01 -0700 Subject: Pipeline refactoring Remove the temp representations and instead use a triple buffer for ImagePresets. Change-Id: I4cdcfbe4941af72b38fe42385085ff4a20eb78cc --- .../filtershow/cache/CachingPipeline.java | 9 ++-- .../filtershow/cache/FilteringPipeline.java | 19 +++++--- .../filtershow/filters/FilterRepresentation.java | 26 ----------- .../filtershow/imageshow/MasterImage.java | 9 ++++ .../gallery3d/filtershow/pipeline/Buffer.java | 22 ++++++++- .../filtershow/pipeline/SharedBuffer.java | 21 +++------ .../filtershow/pipeline/SharedPreset.java | 44 ++++++++++++++++++ .../gallery3d/filtershow/presets/ImagePreset.java | 54 ++++++++++------------ 8 files changed, 121 insertions(+), 83 deletions(-) create mode 100644 src/com/android/gallery3d/filtershow/pipeline/SharedPreset.java (limited to 'src') diff --git a/src/com/android/gallery3d/filtershow/cache/CachingPipeline.java b/src/com/android/gallery3d/filtershow/cache/CachingPipeline.java index 9901e5705..dfba3f710 100644 --- a/src/com/android/gallery3d/filtershow/cache/CachingPipeline.java +++ b/src/com/android/gallery3d/filtershow/cache/CachingPipeline.java @@ -359,16 +359,13 @@ public class CachingPipeline implements PipelineInterface { mFiltersManager.freeFilterResources(preset); Bitmap resizedOriginalBitmap = mResizedOriginalBitmap; - if (updateOriginalAllocation(preset)) { + if (updateOriginalAllocation(preset) || buffer.getProducer() == null) { resizedOriginalBitmap = mResizedOriginalBitmap; - mEnvironment.cache(buffer.getProducer()); buffer.setProducer(resizedOriginalBitmap); + mEnvironment.cache(buffer.getProducer()); } - Bitmap bitmap = null; - if (buffer.getProducer() != null) { - bitmap = buffer.getProducer().getBitmap(); - } + Bitmap bitmap = buffer.getProducer().getBitmap(); long time2 = System.currentTimeMillis(); if (bitmap == null || (bitmap.getWidth() != resizedOriginalBitmap.getWidth()) diff --git a/src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java b/src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java index cac7e056d..7d8481fb5 100644 --- a/src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java +++ b/src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java @@ -27,6 +27,7 @@ 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.pipeline.SharedBuffer; +import com.android.gallery3d.filtershow.pipeline.SharedPreset; import com.android.gallery3d.filtershow.presets.ImagePreset; public class FilteringPipeline implements Handler.Callback { @@ -72,8 +73,6 @@ public class FilteringPipeline implements Handler.Callback { public void handleMessage(Message msg) { switch (msg.what) { case NEW_PRESET: { - SharedBuffer buffer = MasterImage.getImage().getPreviewBuffer(); - buffer.swapConsumer(); MasterImage.getImage().notifyObservers(); if (mHasUnhandledPreviewRequest) { updatePreviewBuffer(); @@ -96,12 +95,18 @@ public class FilteringPipeline implements Handler.Callback { } switch (msg.what) { case COMPUTE_PRESET: { - ImagePreset preset = (ImagePreset) msg.obj; SharedBuffer buffer = MasterImage.getImage().getPreviewBuffer(); - mPreviewPipeline.compute(buffer, preset, COMPUTE_PRESET); - buffer.swapProducer(); - Message uimsg = mUIHandler.obtainMessage(NEW_PRESET); - mUIHandler.sendMessage(uimsg); + SharedPreset preset = MasterImage.getImage().getPreviewPreset(); + ImagePreset renderingPreset = preset.dequeuePreset(); + if (renderingPreset != null) { + mPreviewPipeline.compute(buffer, renderingPreset, COMPUTE_PRESET); + // set the preset we used in the buffer for later inspection UI-side + buffer.getProducer().setPreset(renderingPreset); + buffer.getProducer().sync(); + buffer.swapProducer(); // push back the result + Message uimsg = mUIHandler.obtainMessage(NEW_PRESET); + mUIHandler.sendMessage(uimsg); + } break; } case COMPUTE_RENDERING_REQUEST: diff --git a/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java index a60410d2b..e6018bb75 100644 --- a/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java +++ b/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java @@ -47,8 +47,6 @@ public class FilterRepresentation implements Cloneable { public static final byte TYPE_TINYPLANET = 6; protected static final String NAME_TAG = "Name"; - private FilterRepresentation mTempRepresentation = null; - public FilterRepresentation(String name) { mName = name; } @@ -67,8 +65,6 @@ public class FilterRepresentation implements Cloneable { representation.setShowParameterValue(showParameterValue()); representation.mSerializationName = mSerializationName; - representation.mTempRepresentation = - mTempRepresentation != null ? mTempRepresentation.clone() : null; if (DEBUG) { Log.v(LOGTAG, "cloning from <" + this + "> to <" + representation + ">"); } @@ -140,28 +136,6 @@ public class FilterRepresentation implements Cloneable { public void useParametersFrom(FilterRepresentation a) { } - public void clearTempRepresentation() { - mTempRepresentation = null; - } - - public synchronized void updateTempParametersFrom(FilterRepresentation representation) { - if (mTempRepresentation == null) { - try { - mTempRepresentation = representation.clone(); - } catch (CloneNotSupportedException e) { - e.printStackTrace(); - } - } else { - mTempRepresentation.useParametersFrom(representation); - } - } - - public synchronized void synchronizeRepresentation() { - if (mTempRepresentation != null) { - useParametersFrom(mTempRepresentation); - } - } - public boolean allowsSingleInstanceOnly() { return false; } diff --git a/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java b/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java index 76670754e..bc208887f 100644 --- a/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java +++ b/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java @@ -35,6 +35,7 @@ import com.android.gallery3d.filtershow.filters.FilterRepresentation; import com.android.gallery3d.filtershow.filters.ImageFilter; import com.android.gallery3d.filtershow.pipeline.Buffer; import com.android.gallery3d.filtershow.pipeline.SharedBuffer; +import com.android.gallery3d.filtershow.pipeline.SharedPreset; import com.android.gallery3d.filtershow.presets.ImagePreset; import com.android.gallery3d.filtershow.state.StateAdapter; @@ -58,6 +59,7 @@ public class MasterImage implements RenderingRequestCaller { private ImagePreset mFiltersOnlyPreset = null; private SharedBuffer mPreviewBuffer = new SharedBuffer(); + private SharedPreset mPreviewPreset = new SharedPreset(); private Bitmap mGeometryOnlyBitmap = null; private Bitmap mFiltersOnlyBitmap = null; @@ -255,6 +257,10 @@ public class MasterImage implements RenderingRequestCaller { return mPreviewBuffer; } + public SharedPreset getPreviewPreset() { + return mPreviewPreset; + } + public void setOriginalGeometry(Bitmap originalBitmapLarge) { GeometryMetadata geo = getPreset().getGeometry(); float w = originalBitmapLarge.getWidth(); @@ -266,6 +272,7 @@ public class MasterImage implements RenderingRequestCaller { } public Bitmap getFilteredImage() { + mPreviewBuffer.swapConsumerIfNeeded(); // get latest bitmap Buffer consumer = mPreviewBuffer.getConsumer(); if (consumer != null) { return consumer.getBitmap(); @@ -349,6 +356,7 @@ public class MasterImage implements RenderingRequestCaller { } public void invalidatePreview() { + mPreviewPreset.enqueuePreset(mPreset); mPreviewBuffer.invalidate(); invalidatePartialPreview(); invalidateHighresPreview(); @@ -554,4 +562,5 @@ public class MasterImage implements RenderingRequestCaller { public ImagePreset getLoadedPreset() { return mLoadedPreset; } + } diff --git a/src/com/android/gallery3d/filtershow/pipeline/Buffer.java b/src/com/android/gallery3d/filtershow/pipeline/Buffer.java index 72685167a..c6dbdb75a 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/Buffer.java +++ b/src/com/android/gallery3d/filtershow/pipeline/Buffer.java @@ -20,16 +20,21 @@ import android.graphics.Bitmap; import android.support.v8.renderscript.Allocation; import android.support.v8.renderscript.RenderScript; import com.android.gallery3d.filtershow.cache.CachingPipeline; +import com.android.gallery3d.filtershow.presets.ImagePreset; public class Buffer { + private static final String LOGTAG = "Buffer"; private Bitmap mBitmap; private Allocation mAllocation; private boolean mUseAllocation = false; private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888; + private ImagePreset mPreset; public Buffer(Bitmap bitmap) { RenderScript rs = CachingPipeline.getRenderScriptContext(); - mBitmap = bitmap.copy(BITMAP_CONFIG, true); + if (bitmap != null) { + mBitmap = bitmap.copy(BITMAP_CONFIG, true); + } if (mUseAllocation) { // TODO: recreate the allocation when the RS context changes mAllocation = Allocation.createFromBitmap(rs, mBitmap, @@ -38,6 +43,10 @@ public class Buffer { } } + public void setBitmap(Bitmap bitmap) { + mBitmap = bitmap.copy(BITMAP_CONFIG, true); + } + public Bitmap getBitmap() { return mBitmap; } @@ -52,5 +61,16 @@ public class Buffer { } } + public ImagePreset getPreset() { + return mPreset; + } + + public void setPreset(ImagePreset preset) { + if ((mPreset == null) || (!mPreset.same(preset))) { + mPreset = new ImagePreset(preset); + } else { + mPreset.updateWith(preset); + } + } } diff --git a/src/com/android/gallery3d/filtershow/pipeline/SharedBuffer.java b/src/com/android/gallery3d/filtershow/pipeline/SharedBuffer.java index 587174668..98e69f60e 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/SharedBuffer.java +++ b/src/com/android/gallery3d/filtershow/pipeline/SharedBuffer.java @@ -17,7 +17,6 @@ package com.android.gallery3d.filtershow.pipeline; import android.graphics.Bitmap; -import android.util.Log; public class SharedBuffer { @@ -26,15 +25,15 @@ public class SharedBuffer { private volatile Buffer mProducer = null; private volatile Buffer mConsumer = null; private volatile Buffer mIntermediate = null; - private volatile boolean mNeedsSwap = false; + private volatile boolean mNeedsSwap = false; private volatile boolean mNeedsRepaint = true; - public SharedBuffer() { - } - - public synchronized void setProducer(Bitmap producer) { - mProducer = new Buffer(producer); + public void setProducer(Bitmap producer) { + Buffer buffer = new Buffer(producer); + synchronized (this) { + mProducer = buffer; + } } public synchronized Buffer getProducer() { @@ -46,22 +45,16 @@ public class SharedBuffer { } public synchronized void swapProducer() { - if (mProducer != null) { - mProducer.sync(); - } Buffer intermediate = mIntermediate; mIntermediate = mProducer; mProducer = intermediate; mNeedsSwap = true; } - public synchronized void swapConsumer() { + public synchronized void swapConsumerIfNeeded() { if (!mNeedsSwap) { return; } - if (mConsumer != null) { - mConsumer.sync(); - } Buffer intermediate = mIntermediate; mIntermediate = mConsumer; mConsumer = intermediate; diff --git a/src/com/android/gallery3d/filtershow/pipeline/SharedPreset.java b/src/com/android/gallery3d/filtershow/pipeline/SharedPreset.java new file mode 100644 index 000000000..e87469458 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/pipeline/SharedPreset.java @@ -0,0 +1,44 @@ +/* + * 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.pipeline; + +import com.android.gallery3d.filtershow.presets.ImagePreset; + +public class SharedPreset { + + private volatile ImagePreset mProducerPreset = null; + private volatile ImagePreset mConsumerPreset = null; + private volatile ImagePreset mIntermediatePreset = null; + + public synchronized void enqueuePreset(ImagePreset preset) { + if (mProducerPreset == null || (!mProducerPreset.same(preset))) { + mProducerPreset = new ImagePreset(preset); + } else { + mProducerPreset.updateWith(preset); + } + ImagePreset temp = mIntermediatePreset; + mIntermediatePreset = mProducerPreset; + mProducerPreset = temp; + } + + public synchronized ImagePreset dequeuePreset() { + ImagePreset temp = mConsumerPreset; + mConsumerPreset = mIntermediatePreset; + mIntermediatePreset = temp; + return mConsumerPreset; + } +} diff --git a/src/com/android/gallery3d/filtershow/presets/ImagePreset.java b/src/com/android/gallery3d/filtershow/presets/ImagePreset.java index 4ec39f765..d36bafd43 100644 --- a/src/com/android/gallery3d/filtershow/presets/ImagePreset.java +++ b/src/com/android/gallery3d/filtershow/presets/ImagePreset.java @@ -147,17 +147,15 @@ public class ImagePreset { if (representation == null) { return; } - synchronized (mFilters) { - if (representation instanceof GeometryMetadata) { - setGeometry((GeometryMetadata) representation); - } else { - int position = getPositionForRepresentation(representation); - if (position == -1) { - return; - } - FilterRepresentation old = mFilters.elementAt(position); - old.updateTempParametersFrom(representation); + if (representation instanceof GeometryMetadata) { + setGeometry((GeometryMetadata) representation); + } else { + int position = getPositionForRepresentation(representation); + if (position == -1) { + return; } + FilterRepresentation old = mFilters.elementAt(position); + old.useParametersFrom(representation); } MasterImage.getImage().invalidatePreview(); fillImageStateAdapter(MasterImage.getImage().getState()); @@ -175,7 +173,7 @@ public class ImagePreset { return mDoApplyFilters; } - public synchronized GeometryMetadata getGeometry() { + public GeometryMetadata getGeometry() { for (FilterRepresentation representation : mFilters) { if (representation instanceof GeometryMetadata) { return (GeometryMetadata) representation; @@ -223,7 +221,7 @@ public class ImagePreset { return true; } - public synchronized void setGeometry(GeometryMetadata representation) { + public void setGeometry(GeometryMetadata representation) { GeometryMetadata geoData = getGeometry(); if (geoData != representation) { geoData.set(representation); @@ -425,7 +423,6 @@ public class ImagePreset { // Returns a new bitmap. if (mDoApplyGeometry) { GeometryMetadata geoData = getGeometry(); - geoData.synchronizeRepresentation(); bitmap = environment.applyRepresentation(geoData, bitmap); } return bitmap; @@ -436,7 +433,6 @@ public class ImagePreset { FilterRepresentation border = getFilterRepresentationForType( FilterRepresentation.TYPE_BORDER); if (border != null && mDoApplyGeometry) { - border.synchronizeRepresentation(); bitmap = environment.applyRepresentation(border, bitmap); if (environment.getQuality() == FilterEnvironment.QUALITY_FINAL) { UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR, @@ -463,11 +459,7 @@ public class ImagePreset { "SaveFilters", "Total", to - from + 1); } for (int i = from; i < to; i++) { - FilterRepresentation representation = null; - synchronized (mFilters) { - representation = mFilters.elementAt(i); - representation.synchronizeRepresentation(); - } + FilterRepresentation representation = mFilters.elementAt(i); if (representation instanceof GeometryMetadata) { // skip the geometry as it's already applied. continue; @@ -496,7 +488,6 @@ public class ImagePreset { FilterRepresentation border = getFilterRepresentationForType( FilterRepresentation.TYPE_BORDER); if (border != null && mDoApplyGeometry) { - border.synchronizeRepresentation(); // TODO: should keep the bitmap around Allocation bitmapIn = in; if (copyOut) { @@ -518,11 +509,7 @@ public class ImagePreset { to = mFilters.size(); } for (int i = from; i < to; i++) { - FilterRepresentation representation = null; - synchronized (mFilters) { - representation = mFilters.elementAt(i); - representation.synchronizeRepresentation(); - } + FilterRepresentation representation = mFilters.elementAt(i); if (representation instanceof GeometryMetadata) { // skip the geometry as it's already applied. continue; @@ -544,10 +531,7 @@ public class ImagePreset { return false; } for (int i = 0; i < mFilters.size(); i++) { - FilterRepresentation representation = null; - synchronized (mFilters) { - representation = mFilters.elementAt(i); - } + FilterRepresentation representation = mFilters.elementAt(i); if (representation instanceof GeometryMetadata && ((GeometryMetadata) representation).hasModifications()) { return false; @@ -703,4 +687,16 @@ public class ImagePreset { FiltersManager filtersManager = FiltersManager.getManager(); return filtersManager.createFilterFromName(name); } + + public void updateWith(ImagePreset preset) { + if (preset.mFilters.size() != mFilters.size()) { + Log.e(LOGTAG, "Updating a preset with an incompatible one"); + return; + } + for (int i = 0; i < mFilters.size(); i++) { + FilterRepresentation destRepresentation = mFilters.elementAt(i); + FilterRepresentation sourceRepresentation = preset.mFilters.elementAt(i); + destRepresentation.useParametersFrom(sourceRepresentation); + } + } } -- cgit v1.2.3