PatchCache.cpp revision 3b748a44c6bd2ea05fe16839caf73dbe50bd7ae9
1f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy/*
2f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy * Copyright (C) 2010 The Android Open Source Project
3f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy *
4f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy * Licensed under the Apache License, Version 2.0 (the "License");
5f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy * you may not use this file except in compliance with the License.
6f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy * You may obtain a copy of the License at
7f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy *
8f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy *      http://www.apache.org/licenses/LICENSE-2.0
9f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy *
10f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy * Unless required by applicable law or agreed to in writing, software
11f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy * distributed under the License is distributed on an "AS IS" BASIS,
12f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy * See the License for the specific language governing permissions and
14f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy * limitations under the License.
15f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy */
16f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy
17f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy#define LOG_TAG "OpenGLRenderer"
18f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy
193b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy#include <utils/JenkinsHash.h>
20f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy#include <utils/Log.h>
21f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy
223b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy#include "Caches.h"
23f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy#include "PatchCache.h"
24fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy#include "Properties.h"
25f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy
26f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guynamespace android {
27f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guynamespace uirenderer {
28f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy
29f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy///////////////////////////////////////////////////////////////////////////////
30f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy// Constructors/destructor
31f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy///////////////////////////////////////////////////////////////////////////////
32f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy
333b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain GuyPatchCache::PatchCache(): mCache(LruCache<PatchDescription, Patch*>::kUnlimitedCapacity) {
343b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    char property[PROPERTY_VALUE_MAX];
353b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    if (property_get(PROPERTY_PATCH_CACHE_SIZE, property, NULL) > 0) {
363b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        INIT_LOGD("  Setting patch cache size to %skB", property);
373b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        mMaxSize = KB(atoi(property));
383b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    } else {
393b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        INIT_LOGD("  Using default patch cache size of %.2fkB", DEFAULT_PATCH_CACHE_SIZE);
403b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        mMaxSize = KB(DEFAULT_PATCH_CACHE_SIZE);
413b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    }
423b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    mSize = 0;
43f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy}
44f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy
45f7f93556c8fcc640ab5adef79d021a80a72a645aRomain GuyPatchCache::~PatchCache() {
46f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy    clear();
47f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy}
48f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy
493b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guyvoid PatchCache::init(Caches& caches) {
503b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    glGenBuffers(1, &mMeshBuffer);
513b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    caches.bindMeshBuffer(mMeshBuffer);
523b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    caches.resetVertexPointers();
533b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
543b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    glBufferData(GL_ARRAY_BUFFER, mMaxSize, NULL, GL_DYNAMIC_DRAW);
553b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy}
563b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
57f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy///////////////////////////////////////////////////////////////////////////////
58f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy// Caching
59f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy///////////////////////////////////////////////////////////////////////////////
60f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy
613b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guyhash_t PatchCache::PatchDescription::hash() const {
623b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    uint32_t hash = JenkinsHashMix(0, android::hash_type(mPatch));
633b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    hash = JenkinsHashMix(hash, mBitmapWidth);
643b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    hash = JenkinsHashMix(hash, mBitmapHeight);
653b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    hash = JenkinsHashMix(hash, mPixelWidth);
663b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    hash = JenkinsHashMix(hash, mPixelHeight);
673b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    return JenkinsHashWhiten(hash);
683b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy}
6913ba0054846ce630ca31e8f26169fd9388faee02Romain Guy
703b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guyint PatchCache::PatchDescription::compare(const PatchCache::PatchDescription& lhs,
713b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy            const PatchCache::PatchDescription& rhs) {
723b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    return memcmp(&lhs, &rhs, sizeof(PatchDescription));
7313ba0054846ce630ca31e8f26169fd9388faee02Romain Guy}
7413ba0054846ce630ca31e8f26169fd9388faee02Romain Guy
75f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guyvoid PatchCache::clear() {
763b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    glDeleteBuffers(1, &mMeshBuffer);
773b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    clearCache();
783b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    mSize = 0;
793b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy}
803b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
813b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guyvoid PatchCache::clearCache() {
823b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    LruCache<PatchDescription, Patch*>::Iterator i(mCache);
833b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    while (i.next()) {
843b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        ALOGD("Delete %p", i.value());
853b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        delete i.value();
862728f961614a385df1f056fc24803a9f65c90fabRomain Guy    }
87f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy    mCache.clear();
88f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy}
89f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy
903b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guyconst Patch* PatchCache::get(const AssetAtlas::Entry* entry,
913b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        const uint32_t bitmapWidth, const uint32_t bitmapHeight,
923b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        const float pixelWidth, const float pixelHeight, const Res_png_9patch* patch) {
934bb942083a0d4db746adf95349108dd8ef842e32Romain Guy
943b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    const PatchDescription description(bitmapWidth, bitmapHeight, pixelWidth, pixelHeight, patch);
953b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    const Patch* mesh = mCache.get(description);
964bb942083a0d4db746adf95349108dd8ef842e32Romain Guy
973b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    if (!mesh) {
983b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        Patch* newMesh = new Patch();
993b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        TextureVertex* vertices;
1003b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
1013b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        if (entry) {
1023b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy            vertices = newMesh->createMesh(bitmapWidth, bitmapHeight,
1033b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy                    0.0f, 0.0f, pixelWidth, pixelHeight, entry->uvMapper, patch);
1043b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        } else {
1053b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy            vertices = newMesh->createMesh(bitmapWidth, bitmapHeight,
1063b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy                    0.0f, 0.0f, pixelWidth, pixelHeight, patch);
1074bb942083a0d4db746adf95349108dd8ef842e32Romain Guy        }
1082728f961614a385df1f056fc24803a9f65c90fabRomain Guy
1093b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        if (vertices) {
1103b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy            Caches& caches = Caches::getInstance();
1113b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy            caches.bindMeshBuffer(mMeshBuffer);
1123b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy            caches.resetVertexPointers();
1133b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
1143b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy            // TODO: Simply remove the oldest items until we have enough room
1153b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy            // This will require to keep a list of free blocks in the VBO
1163b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy            uint32_t size = newMesh->getSize();
1173b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy            if (mSize + size > mMaxSize) {
1183b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy                clearCache();
1193b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy                glBufferData(GL_ARRAY_BUFFER, mMaxSize, NULL, GL_DYNAMIC_DRAW);
1203b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy                mSize = 0;
1213b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy            }
122054dc1840941665e32036f9523df51720ad069c8Romain Guy
1233b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy            newMesh->offset = (GLintptr) mSize;
1243b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy            newMesh->textureOffset = newMesh->offset + gMeshTextureOffset;
1253b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy            mSize += size;
1262728f961614a385df1f056fc24803a9f65c90fabRomain Guy
1273b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy            glBufferSubData(GL_ARRAY_BUFFER, newMesh->offset, size, vertices);
128f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy
1293b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy            delete[] vertices;
1302728f961614a385df1f056fc24803a9f65c90fabRomain Guy        }
1312728f961614a385df1f056fc24803a9f65c90fabRomain Guy
1323b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        mCache.put(description, newMesh);
1333b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        return newMesh;
134f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy    }
135f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy
136f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy    return mesh;
137f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy}
138f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy
139f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy}; // namespace uirenderer
140f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy}; // namespace android
141