PatchCache.cpp revision 7d9b1b3c02eb1ffd99742ecb7b69e3ab97d2ba18
1/* 2 * Copyright (C) 2010 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#define LOG_TAG "OpenGLRenderer" 18 19#include <utils/JenkinsHash.h> 20#include <utils/Log.h> 21 22#include "Caches.h" 23#include "PatchCache.h" 24#include "Properties.h" 25 26namespace android { 27namespace uirenderer { 28 29/////////////////////////////////////////////////////////////////////////////// 30// Constructors/destructor 31/////////////////////////////////////////////////////////////////////////////// 32 33PatchCache::PatchCache(): mCache(LruCache<PatchDescription, Patch*>::kUnlimitedCapacity) { 34 char property[PROPERTY_VALUE_MAX]; 35 if (property_get(PROPERTY_PATCH_CACHE_SIZE, property, NULL) > 0) { 36 INIT_LOGD(" Setting patch cache size to %skB", property); 37 mMaxSize = KB(atoi(property)); 38 } else { 39 INIT_LOGD(" Using default patch cache size of %.2fkB", DEFAULT_PATCH_CACHE_SIZE); 40 mMaxSize = KB(DEFAULT_PATCH_CACHE_SIZE); 41 } 42 mSize = 0; 43 mMeshBuffer = 0; 44} 45 46PatchCache::~PatchCache() { 47 clear(); 48} 49 50void PatchCache::init(Caches& caches) { 51 bool created = false; 52 if (!mMeshBuffer) { 53 glGenBuffers(1, &mMeshBuffer); 54 created = true; 55 } 56 57 caches.bindMeshBuffer(mMeshBuffer); 58 caches.resetVertexPointers(); 59 60 if (created) { 61 glBufferData(GL_ARRAY_BUFFER, mMaxSize, NULL, GL_DYNAMIC_DRAW); 62 } 63} 64 65/////////////////////////////////////////////////////////////////////////////// 66// Caching 67/////////////////////////////////////////////////////////////////////////////// 68 69hash_t PatchCache::PatchDescription::hash() const { 70 uint32_t hash = JenkinsHashMix(0, android::hash_type(mPatch)); 71 hash = JenkinsHashMix(hash, mBitmapWidth); 72 hash = JenkinsHashMix(hash, mBitmapHeight); 73 hash = JenkinsHashMix(hash, mPixelWidth); 74 hash = JenkinsHashMix(hash, mPixelHeight); 75 return JenkinsHashWhiten(hash); 76} 77 78int PatchCache::PatchDescription::compare(const PatchCache::PatchDescription& lhs, 79 const PatchCache::PatchDescription& rhs) { 80 return memcmp(&lhs, &rhs, sizeof(PatchDescription)); 81} 82 83void PatchCache::clear() { 84 clearCache(); 85 86 if (mMeshBuffer) { 87 Caches::getInstance().unbindMeshBuffer(); 88 glDeleteBuffers(1, &mMeshBuffer); 89 mMeshBuffer = 0; 90 mSize = 0; 91 } 92} 93 94void PatchCache::clearCache() { 95 LruCache<PatchDescription, Patch*>::Iterator i(mCache); 96 while (i.next()) { 97 delete i.value(); 98 } 99 mCache.clear(); 100} 101 102const Patch* PatchCache::get(const AssetAtlas::Entry* entry, 103 const uint32_t bitmapWidth, const uint32_t bitmapHeight, 104 const float pixelWidth, const float pixelHeight, const Res_png_9patch* patch) { 105 106 const PatchDescription description(bitmapWidth, bitmapHeight, pixelWidth, pixelHeight, patch); 107 const Patch* mesh = mCache.get(description); 108 109 if (!mesh) { 110 Patch* newMesh = new Patch(); 111 TextureVertex* vertices; 112 113 if (entry) { 114 vertices = newMesh->createMesh(bitmapWidth, bitmapHeight, 115 0.0f, 0.0f, pixelWidth, pixelHeight, entry->uvMapper, patch); 116 } else { 117 vertices = newMesh->createMesh(bitmapWidth, bitmapHeight, 118 0.0f, 0.0f, pixelWidth, pixelHeight, patch); 119 } 120 121 if (vertices) { 122 // This call ensures the VBO exists and that it is bound 123 init(Caches::getInstance()); 124 125 // TODO: Simply remove the oldest items until we have enough room 126 // This will require to keep a list of free blocks in the VBO 127 uint32_t size = newMesh->getSize(); 128 if (mSize + size > mMaxSize) { 129 clearCache(); 130 glBufferData(GL_ARRAY_BUFFER, mMaxSize, NULL, GL_DYNAMIC_DRAW); 131 mSize = 0; 132 } 133 134 newMesh->offset = (GLintptr) mSize; 135 newMesh->textureOffset = newMesh->offset + gMeshTextureOffset; 136 mSize += size; 137 138 glBufferSubData(GL_ARRAY_BUFFER, newMesh->offset, size, vertices); 139 140 delete[] vertices; 141 } 142 143 mCache.put(description, newMesh); 144 return newMesh; 145 } 146 147 return mesh; 148} 149 150}; // namespace uirenderer 151}; // namespace android 152