PatchCache.cpp revision 1f8a0db348f6c7bf2d1f55065472c913677f3d69
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}
44
45PatchCache::~PatchCache() {
46    clear();
47}
48
49void PatchCache::init(Caches& caches) {
50    glGenBuffers(1, &mMeshBuffer);
51    caches.bindMeshBuffer(mMeshBuffer);
52    caches.resetVertexPointers();
53
54    glBufferData(GL_ARRAY_BUFFER, mMaxSize, NULL, GL_DYNAMIC_DRAW);
55}
56
57///////////////////////////////////////////////////////////////////////////////
58// Caching
59///////////////////////////////////////////////////////////////////////////////
60
61hash_t PatchCache::PatchDescription::hash() const {
62    uint32_t hash = JenkinsHashMix(0, android::hash_type(mPatch));
63    hash = JenkinsHashMix(hash, mBitmapWidth);
64    hash = JenkinsHashMix(hash, mBitmapHeight);
65    hash = JenkinsHashMix(hash, mPixelWidth);
66    hash = JenkinsHashMix(hash, mPixelHeight);
67    return JenkinsHashWhiten(hash);
68}
69
70int PatchCache::PatchDescription::compare(const PatchCache::PatchDescription& lhs,
71            const PatchCache::PatchDescription& rhs) {
72    return memcmp(&lhs, &rhs, sizeof(PatchDescription));
73}
74
75void PatchCache::clear() {
76    glDeleteBuffers(1, &mMeshBuffer);
77    clearCache();
78    mSize = 0;
79}
80
81void PatchCache::clearCache() {
82    LruCache<PatchDescription, Patch*>::Iterator i(mCache);
83    while (i.next()) {
84        delete i.value();
85    }
86    mCache.clear();
87}
88
89const Patch* PatchCache::get(const AssetAtlas::Entry* entry,
90        const uint32_t bitmapWidth, const uint32_t bitmapHeight,
91        const float pixelWidth, const float pixelHeight, const Res_png_9patch* patch) {
92
93    const PatchDescription description(bitmapWidth, bitmapHeight, pixelWidth, pixelHeight, patch);
94    const Patch* mesh = mCache.get(description);
95
96    if (!mesh) {
97        Patch* newMesh = new Patch();
98        TextureVertex* vertices;
99
100        if (entry) {
101            vertices = newMesh->createMesh(bitmapWidth, bitmapHeight,
102                    0.0f, 0.0f, pixelWidth, pixelHeight, entry->uvMapper, patch);
103        } else {
104            vertices = newMesh->createMesh(bitmapWidth, bitmapHeight,
105                    0.0f, 0.0f, pixelWidth, pixelHeight, patch);
106        }
107
108        if (vertices) {
109            Caches& caches = Caches::getInstance();
110            caches.bindMeshBuffer(mMeshBuffer);
111            caches.resetVertexPointers();
112
113            // TODO: Simply remove the oldest items until we have enough room
114            // This will require to keep a list of free blocks in the VBO
115            uint32_t size = newMesh->getSize();
116            if (mSize + size > mMaxSize) {
117                clearCache();
118                glBufferData(GL_ARRAY_BUFFER, mMaxSize, NULL, GL_DYNAMIC_DRAW);
119                mSize = 0;
120            }
121
122            newMesh->offset = (GLintptr) mSize;
123            newMesh->textureOffset = newMesh->offset + gMeshTextureOffset;
124            mSize += size;
125
126            glBufferSubData(GL_ARRAY_BUFFER, newMesh->offset, size, vertices);
127
128            delete[] vertices;
129        }
130
131        mCache.put(description, newMesh);
132        return newMesh;
133    }
134
135    return mesh;
136}
137
138}; // namespace uirenderer
139}; // namespace android
140