1 /* 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 17 package com.android.gallery3d.filtershow.cache; 18 19 import android.graphics.Bitmap; 20 import android.os.*; 21 import android.os.Process; 22 import android.support.v8.renderscript.*; 23 import android.util.Log; 24 25 import com.android.gallery3d.filtershow.filters.FiltersManager; 26 import com.android.gallery3d.filtershow.filters.ImageFilterRS; 27 import com.android.gallery3d.filtershow.imageshow.GeometryMetadata; 28 import com.android.gallery3d.filtershow.imageshow.MasterImage; 29 import com.android.gallery3d.filtershow.presets.ImagePreset; 30 31 public class FilteringPipeline implements Handler.Callback { 32 33 private static volatile FilteringPipeline sPipeline = null; 34 private static final String LOGTAG = "FilteringPipeline"; 35 private boolean DEBUG = false; 36 37 private static long HIRES_DELAY = 300; // in ms 38 39 private volatile boolean mPipelineIsOn = false; 40 41 private CachingPipeline mAccessoryPipeline = null; 42 private CachingPipeline mPreviewPipeline = null; 43 private CachingPipeline mHighresPreviewPipeline = null; 44 45 private HandlerThread mHandlerThread = null; 46 private final static int NEW_PRESET = 0; 47 private final static int NEW_RENDERING_REQUEST = 1; 48 private final static int COMPUTE_PRESET = 2; 49 private final static int COMPUTE_RENDERING_REQUEST = 3; 50 private final static int COMPUTE_PARTIAL_RENDERING_REQUEST = 4; 51 private final static int COMPUTE_HIGHRES_RENDERING_REQUEST = 5; 52 53 private volatile boolean mHasUnhandledPreviewRequest = false; 54 55 private String getType(int value) { 56 if (value == COMPUTE_RENDERING_REQUEST) { 57 return "COMPUTE_RENDERING_REQUEST"; 58 } 59 if (value == COMPUTE_PARTIAL_RENDERING_REQUEST) { 60 return "COMPUTE_PARTIAL_RENDERING_REQUEST"; 61 } 62 if (value == COMPUTE_HIGHRES_RENDERING_REQUEST) { 63 return "COMPUTE_HIGHRES_RENDERING_REQUEST"; 64 } 65 return "UNKNOWN TYPE"; 66 } 67 68 private Handler mProcessingHandler = null; 69 private final Handler mUIHandler = new Handler() { 70 @Override 71 public void handleMessage(Message msg) { 72 switch (msg.what) { 73 case NEW_PRESET: { 74 TripleBufferBitmap buffer = MasterImage.getImage().getDoubleBuffer(); 75 buffer.swapConsumer(); 76 MasterImage.getImage().notifyObservers(); 77 if (mHasUnhandledPreviewRequest) { 78 updatePreviewBuffer(); 79 } 80 break; 81 } 82 case NEW_RENDERING_REQUEST: { 83 RenderingRequest request = (RenderingRequest) msg.obj; 84 request.markAvailable(); 85 break; 86 } 87 } 88 } 89 }; 90 91 @Override 92 public boolean handleMessage(Message msg) { 93 if (!mPipelineIsOn) { 94 return false; 95 } 96 switch (msg.what) { 97 case COMPUTE_PRESET: { 98 ImagePreset preset = (ImagePreset) msg.obj; 99 TripleBufferBitmap buffer = MasterImage.getImage().getDoubleBuffer(); 100 mPreviewPipeline.compute(buffer, preset, COMPUTE_PRESET); 101 buffer.swapProducer(); 102 Message uimsg = mUIHandler.obtainMessage(NEW_PRESET); 103 mUIHandler.sendMessage(uimsg); 104 break; 105 } 106 case COMPUTE_RENDERING_REQUEST: 107 case COMPUTE_PARTIAL_RENDERING_REQUEST: 108 case COMPUTE_HIGHRES_RENDERING_REQUEST: { 109 110 if (DEBUG) { 111 Log.v(LOGTAG, "Compute Request: " + getType(msg.what)); 112 } 113 114 RenderingRequest request = (RenderingRequest) msg.obj; 115 if (msg.what == COMPUTE_HIGHRES_RENDERING_REQUEST) { 116 mHighresPreviewPipeline.render(request); 117 } else { 118 mAccessoryPipeline.render(request); 119 } 120 if (request.getBitmap() != null) { 121 Message uimsg = mUIHandler.obtainMessage(NEW_RENDERING_REQUEST); 122 uimsg.obj = request; 123 mUIHandler.sendMessage(uimsg); 124 } 125 break; 126 } 127 } 128 return false; 129 } 130 131 private FilteringPipeline() { 132 mHandlerThread = new HandlerThread("FilteringPipeline", 133 Process.THREAD_PRIORITY_FOREGROUND); 134 mHandlerThread.start(); 135 mProcessingHandler = new Handler(mHandlerThread.getLooper(), this); 136 mAccessoryPipeline = new CachingPipeline( 137 FiltersManager.getManager(), "Accessory"); 138 mPreviewPipeline = new CachingPipeline( 139 FiltersManager.getPreviewManager(), "Preview"); 140 mHighresPreviewPipeline = new CachingPipeline( 141 FiltersManager.getHighresManager(), "Highres"); 142 } 143 144 public synchronized static FilteringPipeline getPipeline() { 145 if (sPipeline == null) { 146 sPipeline = new FilteringPipeline(); 147 } 148 return sPipeline; 149 } 150 151 public void setOriginal(Bitmap bitmap) { 152 if (mPipelineIsOn) { 153 Log.e(LOGTAG, "setOriginal called after pipeline initialization!"); 154 return; 155 } 156 mAccessoryPipeline.setOriginal(bitmap); 157 mPreviewPipeline.setOriginal(bitmap); 158 mHighresPreviewPipeline.setOriginal(bitmap); 159 } 160 161 public void postRenderingRequest(RenderingRequest request) { 162 if (!mPipelineIsOn) { 163 return; 164 } 165 int type = COMPUTE_RENDERING_REQUEST; 166 if (request.getType() == RenderingRequest.PARTIAL_RENDERING) { 167 type = COMPUTE_PARTIAL_RENDERING_REQUEST; 168 } 169 if (request.getType() == RenderingRequest.HIGHRES_RENDERING) { 170 type = COMPUTE_HIGHRES_RENDERING_REQUEST; 171 } 172 Message msg = mProcessingHandler.obtainMessage(type); 173 msg.obj = request; 174 if (type == COMPUTE_PARTIAL_RENDERING_REQUEST 175 || type == COMPUTE_HIGHRES_RENDERING_REQUEST) { 176 if (mProcessingHandler.hasMessages(msg.what)) { 177 mProcessingHandler.removeMessages(msg.what); 178 } 179 mProcessingHandler.sendMessageDelayed(msg, HIRES_DELAY); 180 } else { 181 mProcessingHandler.sendMessage(msg); 182 } 183 } 184 185 public void updatePreviewBuffer() { 186 if (!mPipelineIsOn) { 187 return; 188 } 189 mHasUnhandledPreviewRequest = true; 190 mHighresPreviewPipeline.stop(); 191 if (mProcessingHandler.hasMessages(COMPUTE_PRESET)) { 192 return; 193 } 194 if (!mPreviewPipeline.needsRepaint()) { 195 return; 196 } 197 if (MasterImage.getImage().getPreset() == null) { 198 return; 199 } 200 Message msg = mProcessingHandler.obtainMessage(COMPUTE_PRESET); 201 msg.obj = MasterImage.getImage().getPreset(); 202 mHasUnhandledPreviewRequest = false; 203 mProcessingHandler.sendMessageAtFrontOfQueue(msg); 204 } 205 206 public void setPreviewScaleFactor(float previewScaleFactor) { 207 mAccessoryPipeline.setPreviewScaleFactor(previewScaleFactor); 208 mPreviewPipeline.setPreviewScaleFactor(previewScaleFactor); 209 mHighresPreviewPipeline.setPreviewScaleFactor(previewScaleFactor); 210 } 211 212 public void setHighResPreviewScaleFactor(float highResPreviewScaleFactor) { 213 mAccessoryPipeline.setHighResPreviewScaleFactor(highResPreviewScaleFactor); 214 mPreviewPipeline.setHighResPreviewScaleFactor(highResPreviewScaleFactor); 215 mHighresPreviewPipeline.setHighResPreviewScaleFactor(highResPreviewScaleFactor); 216 } 217 218 public static synchronized void reset() { 219 sPipeline.mAccessoryPipeline.reset(); 220 sPipeline.mPreviewPipeline.reset(); 221 sPipeline.mHighresPreviewPipeline.reset(); 222 sPipeline.mHandlerThread.quit(); 223 sPipeline = null; 224 } 225 226 public void turnOnPipeline(boolean t) { 227 mPipelineIsOn = t; 228 if (mPipelineIsOn) { 229 assert(mPreviewPipeline.isInitialized()); 230 assert(mAccessoryPipeline.isInitialized()); 231 assert(mHighresPreviewPipeline.isInitialized()); 232 updatePreviewBuffer(); 233 } 234 } 235 } 236