blob: a1dbe8e525783781ddbcf9c5d99f3b2ec44eb051 [file] [log] [blame]
nicolasroard57eedfd2013-01-15 19:57:49 -08001/*
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
17package com.android.gallery3d.filtershow.cache;
18
19import android.graphics.Bitmap;
20import android.os.*;
21import android.os.Process;
Stephen Hines24063432013-01-23 18:38:42 +000022import android.renderscript.Allocation;
23import android.renderscript.Allocation.MipmapControl;
24import android.renderscript.RenderScript;
nicolasroard57eedfd2013-01-15 19:57:49 -080025import android.util.Log;
26
27import com.android.gallery3d.filtershow.filters.ImageFilterRS;
28import com.android.gallery3d.filtershow.imageshow.GeometryMetadata;
29import com.android.gallery3d.filtershow.imageshow.MasterImage;
30import com.android.gallery3d.filtershow.presets.ImagePreset;
31
32public class FilteringPipeline implements Handler.Callback {
33
34 private final static FilteringPipeline gPipeline = new FilteringPipeline();
35 private static final String LOGTAG = "FilteringPipeline";
36 private ImagePreset mPreviousPreset = null;
37 private ImagePreset mPreviousGeometryPreset = null;
38 private ImagePreset mPreviousFiltersPreset = null;
39 private GeometryMetadata mPreviousGeometry = null;
40
41 private Bitmap mOriginalBitmap = null;
42 private Bitmap mResizedOriginalBitmap = null;
43
44 private boolean DEBUG = false;
45
46 private HandlerThread mHandlerThread = null;
47 private final static int NEW_PRESET = 0;
48 private final static int COMPUTE_PRESET = 1;
49 private final static int COMPUTE_GEOMETRY_PRESET = 2;
50 private final static int COMPUTE_FILTERS_PRESET = 3;
51
52 private boolean mProcessing = false;
53
54 private Handler mProcessingHandler = null;
55 private final Handler mUIHandler = new Handler() {
56 @Override
57 public void handleMessage(Message msg) {
58 switch (msg.what) {
59 case NEW_PRESET: {
60 MasterImage.getImage().notifyObservers();
61 mProcessing = false;
62 break;
63 }
64 }
65 }
66 };
67
68 @Override
69 public boolean handleMessage(Message msg) {
70 switch (msg.what) {
71 case COMPUTE_PRESET: {
72 ImagePreset preset = MasterImage.getImage().getPreset();
73 TripleBufferBitmap buffer = MasterImage.getImage().getDoubleBuffer();
74 compute(buffer, preset, COMPUTE_PRESET);
75 Message uimsg = mUIHandler.obtainMessage(NEW_PRESET);
76 mUIHandler.sendMessage(uimsg);
77 break;
78 }
79 case COMPUTE_GEOMETRY_PRESET: {
80 ImagePreset preset = MasterImage.getImage().getGeometryPreset();
81 TripleBufferBitmap buffer = MasterImage.getImage().getGeometryOnlyBuffer();
82 compute(buffer, preset, COMPUTE_GEOMETRY_PRESET);
83 Message uimsg = mUIHandler.obtainMessage(NEW_PRESET);
84 mUIHandler.sendMessage(uimsg);
85 break;
86 }
87 case COMPUTE_FILTERS_PRESET: {
88 ImagePreset preset = MasterImage.getImage().getFiltersOnlyPreset();
89 TripleBufferBitmap buffer = MasterImage.getImage().getFiltersOnlyBuffer();
90 compute(buffer, preset, COMPUTE_FILTERS_PRESET);
91 Message uimsg = mUIHandler.obtainMessage(NEW_PRESET);
92 mUIHandler.sendMessage(uimsg);
93 break;
94 }
95 }
96 return false;
97 }
98
99 private static float RESIZE_FACTOR = 0.8f;
100 private static float MAX_PROCESS_TIME = 100; // in ms
101 private float mResizeFactor = 1.0f;
102 private long mResizeTime = 0;
103
104 private Allocation mOriginalBitmapAllocation = null;
105 private Allocation mOriginalAllocation = null;
106 private Allocation mFiltersOnlyOriginalAllocation = null;
107
108 private FilteringPipeline() {
109 mHandlerThread = new HandlerThread("FilteringPipeline",
110 Process.THREAD_PRIORITY_FOREGROUND);
111 mHandlerThread.start();
112 mProcessingHandler = new Handler(mHandlerThread.getLooper(), this);
113 }
114
115 public static FilteringPipeline getPipeline() {
116 return gPipeline;
117 }
118
119 public synchronized void setOriginal(Bitmap bitmap) {
120 mOriginalBitmap = bitmap;
121 Log.v(LOGTAG,"setOriginal, size " + bitmap.getWidth() + " x " + bitmap.getHeight());
122 updateOriginalAllocation(MasterImage.getImage().getPreset());
123 }
124
125 public synchronized boolean updateOriginalAllocation(ImagePreset preset) {
126 if (mOriginalBitmap == null) {
127 return false;
128 }
129 /*
130 //FIXME: turn back on the on-the-fly resize.
131 int w = (int) (mOriginalBitmap.getWidth() * mResizeFactor);
132 int h = (int) (mOriginalBitmap.getHeight() * mResizeFactor);
133 if (!needsGeometryRepaint() && mResizedOriginalBitmap != null && w == mResizedOriginalBitmap.getWidth()) {
134 return false;
135 }
136 mResizedOriginalBitmap = Bitmap.createScaledBitmap(mOriginalBitmap, w, h, true);
137 */
138 GeometryMetadata geometry = preset.getGeometry();
139 if (mPreviousGeometry != null && geometry.equals(mPreviousGeometry)) {
140 return false;
141 }
142 RenderScript RS = ImageFilterRS.getRenderScriptContext();
143 if (mFiltersOnlyOriginalAllocation != null) {
144 mFiltersOnlyOriginalAllocation.destroy();
145 }
146 mFiltersOnlyOriginalAllocation = Allocation.createFromBitmap(RS, mOriginalBitmap,
Stephen Hines24063432013-01-23 18:38:42 +0000147 MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
nicolasroard57eedfd2013-01-15 19:57:49 -0800148 if (mOriginalAllocation != null) {
149 mOriginalAllocation.destroy();
150 }
151 mResizedOriginalBitmap = preset.applyGeometry(mOriginalBitmap);
152 mOriginalAllocation = Allocation.createFromBitmap(RS, mResizedOriginalBitmap,
Stephen Hines24063432013-01-23 18:38:42 +0000153 MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
nicolasroard57eedfd2013-01-15 19:57:49 -0800154 mPreviousGeometry = new GeometryMetadata(geometry);
155 return true;
156 }
157
158 public synchronized void updatePreviewBuffer() {
159 if (mOriginalAllocation == null) {
160 return;
161 }
162 if (mProcessing) {
163 return;
164 }
165 if (mProcessingHandler.hasMessages(COMPUTE_PRESET)) {
166 return;
167 }
168 if (!needsRepaint()) {
169 return;
170 }
171 Message msg = mProcessingHandler.obtainMessage(COMPUTE_PRESET);
172 mProcessingHandler.sendMessage(msg);
173 mProcessing = true;
174 }
175
176 public void updateGeometryOnlyPreviewBuffer() {
177 if (mOriginalAllocation == null) {
178 return;
179 }
180 if (mProcessing) {
181 return;
182 }
183 if (mProcessingHandler.hasMessages(COMPUTE_GEOMETRY_PRESET)) {
184 return;
185 }
186 if (!needsGeometryRepaint()) {
187 return;
188 }
189 Message msg = mProcessingHandler.obtainMessage(COMPUTE_GEOMETRY_PRESET);
190 mProcessingHandler.sendMessage(msg);
191 mProcessing = true;
192 }
193
194 public void updateFiltersOnlyPreviewBuffer() {
195 if (mOriginalAllocation == null) {
196 return;
197 }
198 if (mProcessing) {
199 return;
200 }
201 if (mProcessingHandler.hasMessages(COMPUTE_FILTERS_PRESET)) {
202 return;
203 }
204 if (!needsFiltersRepaint()) {
205 return;
206 }
207 Message msg = mProcessingHandler.obtainMessage(COMPUTE_FILTERS_PRESET);
208 mProcessingHandler.sendMessage(msg);
209 mProcessing = true;
210 }
211
212 private void compute(TripleBufferBitmap buffer, ImagePreset preset, int type) {
213 String thread = Thread.currentThread().getName();
214 long time = System.currentTimeMillis();
215 if (updateOriginalAllocation(preset)) {
216 buffer.updateBitmaps(mResizedOriginalBitmap);
217 }
218 Bitmap bitmap = buffer.getProducer();
219 long time2 = System.currentTimeMillis();
220
221 if (type != COMPUTE_FILTERS_PRESET) {
222 if (bitmap == null || (bitmap.getWidth() != mResizedOriginalBitmap.getWidth())
223 || (bitmap.getHeight() != mResizedOriginalBitmap.getHeight())) {
224 buffer.updateBitmaps(mResizedOriginalBitmap);
225 bitmap = buffer.getProducer();
226 }
227 mOriginalAllocation.copyTo(bitmap);
228 } else {
229 if (bitmap == null || (bitmap.getWidth() != mOriginalBitmap.getWidth())
230 || (bitmap.getHeight() != mOriginalBitmap.getHeight())) {
231 buffer.updateBitmaps(mOriginalBitmap);
232 bitmap = buffer.getProducer();
233 }
234 mFiltersOnlyOriginalAllocation.copyTo(bitmap);
235 }
236
237 if (mOriginalAllocation == null || bitmap == null) {
238 Log.v(LOGTAG, "exiting compute because mOriginalAllocation: " + mOriginalAllocation + " or bitmap: " + bitmap);
239 return;
240 }
241
242 if (type != COMPUTE_GEOMETRY_PRESET) {
243 bitmap = preset.apply(bitmap);
244 }
245
246 buffer.swapProducer();
247 time = System.currentTimeMillis() - time;
248 time2 = System.currentTimeMillis() - time2;
249 if (DEBUG) {
250 Log.v(LOGTAG, "Applying " + type + " filters to bitmap " + bitmap + " took " + time + " ms, " + time2 + " ms for the filter, on thread " + thread);
251 }
252 if (type == COMPUTE_PRESET) {
253 mPreviousPreset = new ImagePreset(preset);
254 if (mResizeFactor > 0.6 && time > MAX_PROCESS_TIME && (System.currentTimeMillis() + 1000 > mResizeTime)) {
255 mResizeTime = System.currentTimeMillis();
256 mResizeFactor *= RESIZE_FACTOR;
257 }
258 } else if (type == COMPUTE_GEOMETRY_PRESET) {
259 mPreviousGeometryPreset = new ImagePreset(preset);
260 } else if (type == COMPUTE_FILTERS_PRESET) {
261 mPreviousFiltersPreset = new ImagePreset(preset);
262 }
263 }
264
265 private synchronized boolean needsRepaint() {
266 ImagePreset preset = MasterImage.getImage().getPreset();
267 if (preset == null || mPreviousPreset == null) {
268 return true;
269 }
270 if (preset.equals(mPreviousPreset)) {
271 return false;
272 }
273 return true;
274 }
275
276 private synchronized boolean needsGeometryRepaint() {
277 ImagePreset preset = MasterImage.getImage().getPreset();
278 if (preset == null || mPreviousGeometry == null || mPreviousGeometryPreset == null) {
279 return true;
280 }
281 GeometryMetadata geometry = preset.getGeometry();
282 if (geometry.equals(mPreviousGeometryPreset.getGeometry())) {
283 return false;
284 }
285 return true;
286 }
287
288 private synchronized boolean needsFiltersRepaint() {
289 ImagePreset preset = MasterImage.getImage().getPreset();
290 if (preset == null || mPreviousFiltersPreset == null) {
291 return true;
292 }
293 if (preset.equals(mPreviousFiltersPreset)) {
294 return false;
295 }
296 return true;
297 }
298}