diff options
author | Bobby Georgescu <georgescu@google.com> | 2013-02-19 15:49:14 -0800 |
---|---|---|
committer | Bobby Georgescu <georgescu@google.com> | 2013-02-22 12:56:23 -0800 |
commit | 11cfeeddedd61d3c4aa40945fef0bc2d87c7559d (patch) | |
tree | ab09906b8fe29d40768210bbeb5fc16be4a87625 /src/com/android/photos/data | |
parent | 0718d480a144ba0a44c07c48f90e85cf4ec669c6 (diff) | |
download | android_packages_apps_Snap-11cfeeddedd61d3c4aa40945fef0bc2d87c7559d.tar.gz android_packages_apps_Snap-11cfeeddedd61d3c4aa40945fef0bc2d87c7559d.tar.bz2 android_packages_apps_Snap-11cfeeddedd61d3c4aa40945fef0bc2d87c7559d.zip |
Replace various BitmapPools with a smarter unified pool
Make all of gallery use a single shared pool, and pave the
way for making the pool more adaptive based on the current
workload.
Change-Id: Ia32561ad50b1b9716ebe2fd32a7bf02737685dac
Diffstat (limited to 'src/com/android/photos/data')
-rw-r--r-- | src/com/android/photos/data/GalleryBitmapPool.java | 128 | ||||
-rw-r--r-- | src/com/android/photos/data/SparseArrayBitmapPool.java | 146 |
2 files changed, 274 insertions, 0 deletions
diff --git a/src/com/android/photos/data/GalleryBitmapPool.java b/src/com/android/photos/data/GalleryBitmapPool.java new file mode 100644 index 000000000..cddc160fd --- /dev/null +++ b/src/com/android/photos/data/GalleryBitmapPool.java @@ -0,0 +1,128 @@ +/* + * 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.photos.data; + +import android.graphics.Bitmap; +import android.graphics.Point; +import android.util.Pools.Pool; +import android.util.Pools.SimplePool; + +import com.android.photos.data.SparseArrayBitmapPool.Node; + +public class GalleryBitmapPool { + + private static final int CAPACITY_BYTES = 20971520; + private static final int POOL_INDEX_NONE = -1; + private static final int POOL_INDEX_SQUARE = 0; + private static final int POOL_INDEX_PHOTO = 1; + private static final int POOL_INDEX_MISC = 2; + + private static final Point[] COMMON_PHOTO_ASPECT_RATIOS = + { new Point(4, 3), new Point(3, 2), new Point(16, 9) }; + + private int mCapacityBytes; + private SparseArrayBitmapPool [] mPools; + private Pool<Node> mSharedNodePool = new SimplePool<Node>(128); + + private GalleryBitmapPool(int capacityBytes) { + mPools = new SparseArrayBitmapPool[3]; + mPools[POOL_INDEX_SQUARE] = new SparseArrayBitmapPool(capacityBytes / 3, mSharedNodePool); + mPools[POOL_INDEX_PHOTO] = new SparseArrayBitmapPool(capacityBytes / 3, mSharedNodePool); + mPools[POOL_INDEX_MISC] = new SparseArrayBitmapPool(capacityBytes / 3, mSharedNodePool); + mCapacityBytes = capacityBytes; + } + + private static GalleryBitmapPool sInstance; + public static GalleryBitmapPool getInstance() { + if (sInstance == null) { + sInstance = new GalleryBitmapPool(CAPACITY_BYTES); + } + return sInstance; + } + + private SparseArrayBitmapPool getPoolForDimensions(int width, int height) { + int index = getPoolIndexForDimensions(width, height); + if (index == POOL_INDEX_NONE) { + return null; + } else { + return mPools[index]; + } + } + + private int getPoolIndexForDimensions(int width, int height) { + if (width <= 0 || height <= 0) { + return POOL_INDEX_NONE; + } + if (width == height) { + return POOL_INDEX_SQUARE; + } + int min, max; + if (width > height) { + min = height; + max = width; + } else { + min = width; + max = height; + } + for (Point ar : COMMON_PHOTO_ASPECT_RATIOS) { + if (min * ar.x == max * ar.y) { + return POOL_INDEX_PHOTO; + } + } + return POOL_INDEX_MISC; + } + + public synchronized int getCapacity() { + return mCapacityBytes; + } + + public synchronized int getSize() { + int total = 0; + for (SparseArrayBitmapPool p : mPools) { + total += p.getSize(); + } + return total; + } + + public Bitmap get(int width, int height) { + SparseArrayBitmapPool pool = getPoolForDimensions(width, height); + if (pool == null) { + return null; + } else { + return pool.get(width, height); + } + } + + public boolean put(Bitmap b) { + if (b == null) { + return false; + } + SparseArrayBitmapPool pool = getPoolForDimensions(b.getWidth(), b.getHeight()); + if (pool == null) { + b.recycle(); + return false; + } else { + return pool.put(b); + } + } + + public void clear() { + for (SparseArrayBitmapPool p : mPools) { + p.clear(); + } + } +} diff --git a/src/com/android/photos/data/SparseArrayBitmapPool.java b/src/com/android/photos/data/SparseArrayBitmapPool.java new file mode 100644 index 000000000..851259056 --- /dev/null +++ b/src/com/android/photos/data/SparseArrayBitmapPool.java @@ -0,0 +1,146 @@ +/* + * 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.photos.data; + +import android.graphics.Bitmap; +import android.util.SparseArray; + +import android.util.Pools.Pool; + +public class SparseArrayBitmapPool { + + private static final int BITMAPS_TO_KEEP_AFTER_UNNEEDED_HINT = 4; + private int mCapacityBytes; + private SparseArray<Node> mStore = new SparseArray<Node>(); + private int mSizeBytes = 0; + + private Pool<Node> mNodePool; + private Node mPoolNodesHead = null; + private Node mPoolNodesTail = null; + + protected static class Node { + Bitmap bitmap; + Node prevInBucket; + Node nextInBucket; + Node nextInPool; + Node prevInPool; + } + + public SparseArrayBitmapPool(int capacityBytes, Pool<Node> nodePool) { + mCapacityBytes = capacityBytes; + mNodePool = nodePool; + } + + public synchronized void setCapacity(int capacityBytes) { + mCapacityBytes = capacityBytes; + freeUpCapacity(0); + } + + private void freeUpCapacity(int bytesNeeded) { + int targetSize = mCapacityBytes - bytesNeeded; + while (mPoolNodesTail != null && mSizeBytes > targetSize) { + unlinkAndRecycleNode(mPoolNodesTail, true); + } + } + + private void unlinkAndRecycleNode(Node n, boolean recycleBitmap) { + // Remove the node from its spot in its bucket + if (n.prevInBucket != null) { + n.prevInBucket.nextInBucket = n.nextInBucket; + } else { + mStore.put(n.bitmap.getWidth(), n.nextInBucket); + } + if (n.nextInBucket != null) { + n.nextInBucket.prevInBucket = n.prevInBucket; + } + + // Remove the node from its spot in the list of pool nodes + if (n.prevInPool != null) { + n.prevInPool.nextInPool = n.nextInPool; + } else { + mPoolNodesHead = n.nextInPool; + } + if (n.nextInPool != null) { + n.nextInPool.prevInPool = n.prevInPool; + } else { + mPoolNodesTail = n.prevInPool; + } + + // Recycle the node + n.nextInBucket = null; + n.nextInPool = null; + n.prevInBucket = null; + n.prevInPool = null; + mSizeBytes -= n.bitmap.getByteCount(); + if (recycleBitmap) n.bitmap.recycle(); + n.bitmap = null; + mNodePool.release(n); + } + + public synchronized int getCapacity() { + return mCapacityBytes; + } + + public synchronized int getSize() { + return mSizeBytes; + } + + public synchronized Bitmap get(int width, int height) { + Node cur = mStore.get(width); + while (cur != null) { + if (cur.bitmap.getHeight() == height) { + Bitmap b = cur.bitmap; + unlinkAndRecycleNode(cur, false); + return b; + } + cur = cur.nextInBucket; + } + return null; + } + + public synchronized boolean put(Bitmap b) { + if (b == null) { + return false; + } + int bytes = b.getByteCount(); + freeUpCapacity(bytes); + Node newNode = mNodePool.acquire(); + if (newNode == null) { + newNode = new Node(); + } + newNode.bitmap = b; + newNode.prevInBucket = null; + newNode.prevInPool = null; + newNode.nextInPool = mPoolNodesHead; + mPoolNodesHead = newNode; + int key = b.getWidth(); + newNode.nextInBucket = mStore.get(key); + if (newNode.nextInBucket != null) { + newNode.nextInBucket.prevInBucket = newNode; + } + mStore.put(key, newNode); + if (newNode.nextInPool == null) { + mPoolNodesTail = newNode; + } + mSizeBytes += bytes; + return true; + } + + public synchronized void clear() { + freeUpCapacity(mCapacityBytes); + } +} |