130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni/* 230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * Copyright (C) 2011 The Android Open Source Project 330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * 430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * Licensed under the Apache License, Version 2.0 (the "License"); 530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * you may not use this file except in compliance with the License. 630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * You may obtain a copy of the License at 730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * 830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * http://www.apache.org/licenses/LICENSE-2.0 930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * 1030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * Unless required by applicable law or agreed to in writing, software 1130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * distributed under the License is distributed on an "AS IS" BASIS, 1230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * See the License for the specific language governing permissions and 1430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * limitations under the License. 1530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni */ 1630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 1730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 1830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronipackage android.filterfw.core; 1930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 2030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.filterfw.core.Frame; 2130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.filterfw.core.FrameFormat; 2230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.filterfw.core.SimpleFrameManager; 2330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 24489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Rennimport java.util.Map; 25489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Rennimport java.util.SortedMap; 26489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Rennimport java.util.TreeMap; 27489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn 28a3bfbe5389c6146abe318a7add3fa688d69bc01bEino-Ville Talvala/** 29a3bfbe5389c6146abe318a7add3fa688d69bc01bEino-Ville Talvala * @hide 30a3bfbe5389c6146abe318a7add3fa688d69bc01bEino-Ville Talvala */ 3130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronipublic class CachedFrameManager extends SimpleFrameManager { 3230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 33489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn private SortedMap<Integer, Frame> mAvailableFrames; 34489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn private int mStorageCapacity = 24 * 1024 * 1024; // Cap default storage to 24MB 3530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni private int mStorageSize = 0; 36489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn private int mTimeStamp = 0; 3730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 3830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni public CachedFrameManager() { 3930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni super(); 40489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn mAvailableFrames = new TreeMap<Integer, Frame>(); 4130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 4230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 4333d107bf315c9cc01a02a7a4a2c10a01f62e8c85Wei Hua @Override 4430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni public Frame newFrame(FrameFormat format) { 4530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni Frame result = findAvailableFrame(format, Frame.NO_BINDING, 0); 4630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni if (result == null) { 4730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni result = super.newFrame(format); 4830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 495b9eb6d686c439545dafcc8e25e9e3747281c3deEino-Ville Talvala result.setTimestamp(Frame.TIMESTAMP_NOT_SET); 5030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return result; 5130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 5230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 5333d107bf315c9cc01a02a7a4a2c10a01f62e8c85Wei Hua @Override 5430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni public Frame newBoundFrame(FrameFormat format, int bindingType, long bindingId) { 5530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni Frame result = findAvailableFrame(format, bindingType, bindingId); 5630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni if (result == null) { 5730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni result = super.newBoundFrame(format, bindingType, bindingId); 5830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 595b9eb6d686c439545dafcc8e25e9e3747281c3deEino-Ville Talvala result.setTimestamp(Frame.TIMESTAMP_NOT_SET); 6030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return result; 6130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 6230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 6333d107bf315c9cc01a02a7a4a2c10a01f62e8c85Wei Hua @Override 6430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni public Frame retainFrame(Frame frame) { 6530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return super.retainFrame(frame); 6630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 6730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 6833d107bf315c9cc01a02a7a4a2c10a01f62e8c85Wei Hua @Override 6930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni public Frame releaseFrame(Frame frame) { 7030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni if (frame.isReusable()) { 7130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni int refCount = frame.decRefCount(); 72f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn if (refCount == 0 && frame.hasNativeAllocation()) { 7330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni if (!storeFrame(frame)) { 74f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn frame.releaseNativeAllocation(); 7530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 7630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return null; 7730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } else if (refCount < 0) { 7830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni throw new RuntimeException("Frame reference count dropped below 0!"); 7930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 8030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } else { 8130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni super.releaseFrame(frame); 8230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 8330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return frame; 8430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 8530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 86776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn public void clearCache() { 87776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn for (Frame frame : mAvailableFrames.values()) { 88776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn frame.releaseNativeAllocation(); 89776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn } 90776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn mAvailableFrames.clear(); 91776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn } 92776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn 93776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn @Override 94776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn public void tearDown() { 95776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn clearCache(); 96776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn } 97776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn 9830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni private boolean storeFrame(Frame frame) { 9930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni synchronized(mAvailableFrames) { 100489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn // Make sure this frame alone does not exceed capacity 101489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn int frameSize = frame.getFormat().getSize(); 102489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn if (frameSize > mStorageCapacity) { 103489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn return false; 10430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 105489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn 106489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn // Drop frames if adding this frame would exceed capacity 107489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn int newStorageSize = mStorageSize + frameSize; 108489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn while (newStorageSize > mStorageCapacity) { 109489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn dropOldestFrame(); 110489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn newStorageSize = mStorageSize + frameSize; 111489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn } 112489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn 113489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn // Store new frame 11492568796d043c794553e5bcaa797c906899e71f0Marius Renn frame.onFrameStore(); 115489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn mStorageSize = newStorageSize; 116489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn mAvailableFrames.put(mTimeStamp, frame); 117489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn ++mTimeStamp; 118489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn return true; 11930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 12030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 12130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 122489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn private void dropOldestFrame() { 123489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn int oldest = mAvailableFrames.firstKey(); 124489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn Frame frame = mAvailableFrames.get(oldest); 125489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn mStorageSize -= frame.getFormat().getSize(); 126f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn frame.releaseNativeAllocation(); 127489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn mAvailableFrames.remove(oldest); 128489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn } 129489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn 13030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni private Frame findAvailableFrame(FrameFormat format, int bindingType, long bindingId) { 13130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Look for a frame that is compatible with the requested format 13230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni synchronized(mAvailableFrames) { 133489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn for (Map.Entry<Integer, Frame> entry : mAvailableFrames.entrySet()) { 134489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn Frame frame = entry.getValue(); 13530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Check that format is compatible 13630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni if (frame.getFormat().isReplaceableBy(format)) { 13730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Check that binding is compatible (if frame is bound) 138776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn if ((bindingType == frame.getBindingType()) 139776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn && (bindingType == Frame.NO_BINDING || bindingId == frame.getBindingId())) { 14030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // We found one! Take it out of the set of available frames and attach the 14130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // requested format to it. 14230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni super.retainFrame(frame); 143489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn mAvailableFrames.remove(entry.getKey()); 14492568796d043c794553e5bcaa797c906899e71f0Marius Renn frame.onFrameFetch(); 14530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni frame.reset(format); 14630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni mStorageSize -= format.getSize(); 14730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return frame; 14830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 14930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 15030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 15130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 15230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return null; 15330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 154776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn 15530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} 156