/* * Copyright (C) 2010 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. */ #define LOG_TAG "OpenGLRenderer" #include #include #include "Caches.h" #include "PatchCache.h" #include "Properties.h" namespace android { namespace uirenderer { /////////////////////////////////////////////////////////////////////////////// // Constructors/destructor /////////////////////////////////////////////////////////////////////////////// PatchCache::PatchCache(): mCache(LruCache::kUnlimitedCapacity) { char property[PROPERTY_VALUE_MAX]; if (property_get(PROPERTY_PATCH_CACHE_SIZE, property, NULL) > 0) { INIT_LOGD(" Setting patch cache size to %skB", property); mMaxSize = KB(atoi(property)); } else { INIT_LOGD(" Using default patch cache size of %.2fkB", DEFAULT_PATCH_CACHE_SIZE); mMaxSize = KB(DEFAULT_PATCH_CACHE_SIZE); } mSize = 0; } PatchCache::~PatchCache() { clear(); } void PatchCache::init(Caches& caches) { glGenBuffers(1, &mMeshBuffer); caches.bindMeshBuffer(mMeshBuffer); caches.resetVertexPointers(); glBufferData(GL_ARRAY_BUFFER, mMaxSize, NULL, GL_DYNAMIC_DRAW); } /////////////////////////////////////////////////////////////////////////////// // Caching /////////////////////////////////////////////////////////////////////////////// hash_t PatchCache::PatchDescription::hash() const { uint32_t hash = JenkinsHashMix(0, android::hash_type(mPatch)); hash = JenkinsHashMix(hash, mBitmapWidth); hash = JenkinsHashMix(hash, mBitmapHeight); hash = JenkinsHashMix(hash, mPixelWidth); hash = JenkinsHashMix(hash, mPixelHeight); return JenkinsHashWhiten(hash); } int PatchCache::PatchDescription::compare(const PatchCache::PatchDescription& lhs, const PatchCache::PatchDescription& rhs) { return memcmp(&lhs, &rhs, sizeof(PatchDescription)); } void PatchCache::clear() { glDeleteBuffers(1, &mMeshBuffer); clearCache(); mSize = 0; } void PatchCache::clearCache() { LruCache::Iterator i(mCache); while (i.next()) { delete i.value(); } mCache.clear(); } const Patch* PatchCache::get(const AssetAtlas::Entry* entry, const uint32_t bitmapWidth, const uint32_t bitmapHeight, const float pixelWidth, const float pixelHeight, const Res_png_9patch* patch) { const PatchDescription description(bitmapWidth, bitmapHeight, pixelWidth, pixelHeight, patch); const Patch* mesh = mCache.get(description); if (!mesh) { Patch* newMesh = new Patch(); TextureVertex* vertices; if (entry) { vertices = newMesh->createMesh(bitmapWidth, bitmapHeight, 0.0f, 0.0f, pixelWidth, pixelHeight, entry->uvMapper, patch); } else { vertices = newMesh->createMesh(bitmapWidth, bitmapHeight, 0.0f, 0.0f, pixelWidth, pixelHeight, patch); } if (vertices) { Caches& caches = Caches::getInstance(); caches.bindMeshBuffer(mMeshBuffer); caches.resetVertexPointers(); // TODO: Simply remove the oldest items until we have enough room // This will require to keep a list of free blocks in the VBO uint32_t size = newMesh->getSize(); if (mSize + size > mMaxSize) { clearCache(); glBufferData(GL_ARRAY_BUFFER, mMaxSize, NULL, GL_DYNAMIC_DRAW); mSize = 0; } newMesh->offset = (GLintptr) mSize; newMesh->textureOffset = newMesh->offset + gMeshTextureOffset; mSize += size; glBufferSubData(GL_ARRAY_BUFFER, newMesh->offset, size, vertices); delete[] vertices; } mCache.put(description, newMesh); return newMesh; } return mesh; } }; // namespace uirenderer }; // namespace android