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