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"
232dc236b2bae13b9a0ed9b3f7320502aecd7983b3Tom Hudson#include "Patch.h"
24f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy#include "PatchCache.h"
25fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy#include "Properties.h"
2696a5c4c7bab6718524de7253da8309143ab48befChris Craik#include "renderstate/RenderState.h"
27f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy
28f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guynamespace android {
29f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guynamespace uirenderer {
30f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy
31f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy///////////////////////////////////////////////////////////////////////////////
32f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy// Constructors/destructor
33f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy///////////////////////////////////////////////////////////////////////////////
34f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy
3596a5c4c7bab6718524de7253da8309143ab48befChris CraikPatchCache::PatchCache(RenderState& renderState)
3696a5c4c7bab6718524de7253da8309143ab48befChris Craik        : mRenderState(renderState)
3796a5c4c7bab6718524de7253da8309143ab48befChris Craik        , mSize(0)
3896a5c4c7bab6718524de7253da8309143ab48befChris Craik        , mCache(LruCache<PatchDescription, Patch*>::kUnlimitedCapacity)
3996a5c4c7bab6718524de7253da8309143ab48befChris Craik        , mMeshBuffer(0)
4096a5c4c7bab6718524de7253da8309143ab48befChris Craik        , mFreeBlocks(nullptr)
4196a5c4c7bab6718524de7253da8309143ab48befChris Craik        , mGenerationId(0) {
423b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    char property[PROPERTY_VALUE_MAX];
43d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik    if (property_get(PROPERTY_PATCH_CACHE_SIZE, property, nullptr) > 0) {
443b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        INIT_LOGD("  Setting patch cache size to %skB", property);
453b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        mMaxSize = KB(atoi(property));
463b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    } else {
473b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        INIT_LOGD("  Using default patch cache size of %.2fkB", DEFAULT_PATCH_CACHE_SIZE);
483b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        mMaxSize = KB(DEFAULT_PATCH_CACHE_SIZE);
493b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    }
50f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy}
51f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy
52f7f93556c8fcc640ab5adef79d021a80a72a645aRomain GuyPatchCache::~PatchCache() {
53f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy    clear();
54f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy}
55f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy
5696a5c4c7bab6718524de7253da8309143ab48befChris Craikvoid PatchCache::init() {
577d9b1b3c02eb1ffd99742ecb7b69e3ab97d2ba18Romain Guy    bool created = false;
587d9b1b3c02eb1ffd99742ecb7b69e3ab97d2ba18Romain Guy    if (!mMeshBuffer) {
597d9b1b3c02eb1ffd99742ecb7b69e3ab97d2ba18Romain Guy        glGenBuffers(1, &mMeshBuffer);
607d9b1b3c02eb1ffd99742ecb7b69e3ab97d2ba18Romain Guy        created = true;
617d9b1b3c02eb1ffd99742ecb7b69e3ab97d2ba18Romain Guy    }
627d9b1b3c02eb1ffd99742ecb7b69e3ab97d2ba18Romain Guy
6396a5c4c7bab6718524de7253da8309143ab48befChris Craik    mRenderState.meshState().bindMeshBuffer(mMeshBuffer);
6496a5c4c7bab6718524de7253da8309143ab48befChris Craik    mRenderState.meshState().resetVertexPointers();
653b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
667d9b1b3c02eb1ffd99742ecb7b69e3ab97d2ba18Romain Guy    if (created) {
674c2547fa9244e78115cde0a259291053108c3dc7Romain Guy        createVertexBuffer();
687d9b1b3c02eb1ffd99742ecb7b69e3ab97d2ba18Romain Guy    }
693b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy}
703b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
71f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy///////////////////////////////////////////////////////////////////////////////
72f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy// Caching
73f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy///////////////////////////////////////////////////////////////////////////////
74f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy
753b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guyhash_t PatchCache::PatchDescription::hash() const {
763b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    uint32_t hash = JenkinsHashMix(0, android::hash_type(mPatch));
773b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    hash = JenkinsHashMix(hash, mBitmapWidth);
783b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    hash = JenkinsHashMix(hash, mBitmapHeight);
793b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    hash = JenkinsHashMix(hash, mPixelWidth);
803b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    hash = JenkinsHashMix(hash, mPixelHeight);
813b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    return JenkinsHashWhiten(hash);
823b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy}
8313ba0054846ce630ca31e8f26169fd9388faee02Romain Guy
843b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guyint PatchCache::PatchDescription::compare(const PatchCache::PatchDescription& lhs,
853b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy            const PatchCache::PatchDescription& rhs) {
863b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    return memcmp(&lhs, &rhs, sizeof(PatchDescription));
8713ba0054846ce630ca31e8f26169fd9388faee02Romain Guy}
8813ba0054846ce630ca31e8f26169fd9388faee02Romain Guy
89f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guyvoid PatchCache::clear() {
903b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    clearCache();
917d9b1b3c02eb1ffd99742ecb7b69e3ab97d2ba18Romain Guy
927d9b1b3c02eb1ffd99742ecb7b69e3ab97d2ba18Romain Guy    if (mMeshBuffer) {
9396a5c4c7bab6718524de7253da8309143ab48befChris Craik        mRenderState.meshState().unbindMeshBuffer();
947d9b1b3c02eb1ffd99742ecb7b69e3ab97d2ba18Romain Guy        glDeleteBuffers(1, &mMeshBuffer);
957d9b1b3c02eb1ffd99742ecb7b69e3ab97d2ba18Romain Guy        mMeshBuffer = 0;
967d9b1b3c02eb1ffd99742ecb7b69e3ab97d2ba18Romain Guy        mSize = 0;
977d9b1b3c02eb1ffd99742ecb7b69e3ab97d2ba18Romain Guy    }
983b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy}
993b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
1003b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guyvoid PatchCache::clearCache() {
1013b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    LruCache<PatchDescription, Patch*>::Iterator i(mCache);
1023b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    while (i.next()) {
1033b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        delete i.value();
1042728f961614a385df1f056fc24803a9f65c90fabRomain Guy    }
105f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy    mCache.clear();
106e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy
107e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    BufferBlock* block = mFreeBlocks;
108e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    while (block) {
109e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        BufferBlock* next = block->next;
110e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        delete block;
111e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        block = next;
112e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    }
113d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik    mFreeBlocks = nullptr;
114e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy}
115e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy
116e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guyvoid PatchCache::remove(Vector<patch_pair_t>& patchesToRemove, Res_png_9patch* patch) {
117e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    LruCache<PatchDescription, Patch*>::Iterator i(mCache);
118e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    while (i.next()) {
119e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        const PatchDescription& key = i.key();
120e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        if (key.getPatch() == patch) {
121e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy            patchesToRemove.push(patch_pair_t(&key, i.value()));
122e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        }
123e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    }
124e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy}
125e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy
126e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guyvoid PatchCache::removeDeferred(Res_png_9patch* patch) {
127e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    Mutex::Autolock _l(mLock);
1286056e1027107aaa15f51a5ed775ff14c6b664ca3Jens Gulin
1296056e1027107aaa15f51a5ed775ff14c6b664ca3Jens Gulin    // Assert that patch is not already garbage
1306056e1027107aaa15f51a5ed775ff14c6b664ca3Jens Gulin    size_t count = mGarbage.size();
1316056e1027107aaa15f51a5ed775ff14c6b664ca3Jens Gulin    for (size_t i = 0; i < count; i++) {
1326056e1027107aaa15f51a5ed775ff14c6b664ca3Jens Gulin        if (patch == mGarbage[i]) {
133d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik            patch = nullptr;
1346056e1027107aaa15f51a5ed775ff14c6b664ca3Jens Gulin            break;
1356056e1027107aaa15f51a5ed775ff14c6b664ca3Jens Gulin        }
1366056e1027107aaa15f51a5ed775ff14c6b664ca3Jens Gulin    }
137d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik    LOG_ALWAYS_FATAL_IF(patch == nullptr);
1386056e1027107aaa15f51a5ed775ff14c6b664ca3Jens Gulin
139e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    mGarbage.push(patch);
140e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy}
141e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy
142e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guyvoid PatchCache::clearGarbage() {
143e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    Vector<patch_pair_t> patchesToRemove;
144e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy
145e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    { // scope for the mutex
146e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        Mutex::Autolock _l(mLock);
147e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        size_t count = mGarbage.size();
148e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        for (size_t i = 0; i < count; i++) {
14936fad8f6fcfbc2087b910600ed5a6f9741177d00Sangkyu Lee            Res_png_9patch* patch = mGarbage[i];
15036fad8f6fcfbc2087b910600ed5a6f9741177d00Sangkyu Lee            remove(patchesToRemove, patch);
15136fad8f6fcfbc2087b910600ed5a6f9741177d00Sangkyu Lee            // A Res_png_9patch is actually an array of byte that's larger
15236fad8f6fcfbc2087b910600ed5a6f9741177d00Sangkyu Lee            // than sizeof(Res_png_9patch). It must be freed as an array.
15336fad8f6fcfbc2087b910600ed5a6f9741177d00Sangkyu Lee            delete[] (int8_t*) patch;
154e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        }
155e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        mGarbage.clear();
156e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    }
157e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy
158e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    // TODO: We could sort patchesToRemove by offset to merge
159e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    // adjacent free blocks
160e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    for (size_t i = 0; i < patchesToRemove.size(); i++) {
161e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        const patch_pair_t& pair = patchesToRemove[i];
162e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy
1636056e1027107aaa15f51a5ed775ff14c6b664ca3Jens Gulin        // Release the patch and mark the space in the free list
1646056e1027107aaa15f51a5ed775ff14c6b664ca3Jens Gulin        Patch* patch = pair.getSecond();
1658820fd1d82acaefda98ae73ccf61413d5044f9f3Chris Craik        BufferBlock* block = new BufferBlock(patch->positionOffset, patch->getSize());
166e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        block->next = mFreeBlocks;
167e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        mFreeBlocks = block;
168e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy
169e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        mSize -= patch->getSize();
170e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy
171e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        mCache.remove(*pair.getFirst());
1726056e1027107aaa15f51a5ed775ff14c6b664ca3Jens Gulin        delete patch;
173e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    }
174e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy
175e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy#if DEBUG_PATCHES
176e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    if (patchesToRemove.size() > 0) {
177e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        dumpFreeBlocks("Removed garbage");
178e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    }
179e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy#endif
180f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy}
181f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy
1824c2547fa9244e78115cde0a259291053108c3dc7Romain Guyvoid PatchCache::createVertexBuffer() {
183d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik    glBufferData(GL_ARRAY_BUFFER, mMaxSize, nullptr, GL_DYNAMIC_DRAW);
1844c2547fa9244e78115cde0a259291053108c3dc7Romain Guy    mSize = 0;
185e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    mFreeBlocks = new BufferBlock(0, mMaxSize);
1864c2547fa9244e78115cde0a259291053108c3dc7Romain Guy    mGenerationId++;
1874c2547fa9244e78115cde0a259291053108c3dc7Romain Guy}
1884c2547fa9244e78115cde0a259291053108c3dc7Romain Guy
189e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy/**
190e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy * Sets the mesh's offsets and copies its associated vertices into
191e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy * the mesh buffer (VBO).
192e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy */
1938820fd1d82acaefda98ae73ccf61413d5044f9f3Chris Craikvoid PatchCache::setupMesh(Patch* newMesh) {
194e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    // This call ensures the VBO exists and that it is bound
19596a5c4c7bab6718524de7253da8309143ab48befChris Craik    init();
196e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy
197e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    // If we're running out of space, let's clear the entire cache
198e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    uint32_t size = newMesh->getSize();
199e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    if (mSize + size > mMaxSize) {
200e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        clearCache();
201e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        createVertexBuffer();
202e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    }
203e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy
204e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    // Find a block where we can fit the mesh
205d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik    BufferBlock* previous = nullptr;
206e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    BufferBlock* block = mFreeBlocks;
207e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    while (block) {
208e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        // The mesh fits
209e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        if (block->size >= size) {
210e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy            break;
211e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        }
212e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        previous = block;
213e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        block = block->next;
214e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    }
215e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy
216e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    // We have enough space left in the buffer, but it's
217e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    // too fragmented, let's clear the cache
218e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    if (!block) {
219e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        clearCache();
220e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        createVertexBuffer();
221d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik        previous = nullptr;
222e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        block = mFreeBlocks;
223e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    }
224e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy
225e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    // Copy the 9patch mesh in the VBO
2268820fd1d82acaefda98ae73ccf61413d5044f9f3Chris Craik    newMesh->positionOffset = (GLintptr) (block->offset);
2278820fd1d82acaefda98ae73ccf61413d5044f9f3Chris Craik    newMesh->textureOffset = newMesh->positionOffset + kMeshTextureOffset;
2288820fd1d82acaefda98ae73ccf61413d5044f9f3Chris Craik    glBufferSubData(GL_ARRAY_BUFFER, newMesh->positionOffset, size, newMesh->vertices.get());
229e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy
230e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    // Remove the block since we've used it entirely
231e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    if (block->size == size) {
232e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        if (previous) {
233e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy            previous->next = block->next;
234e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        } else {
235e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy            mFreeBlocks = block->next;
236e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        }
2376056e1027107aaa15f51a5ed775ff14c6b664ca3Jens Gulin        delete block;
238e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    } else {
239e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        // Resize the block now that it's occupied
240e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        block->offset += size;
241e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        block->size -= size;
242e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    }
243e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy
244e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    mSize += size;
245e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy}
246e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy
2478820fd1d82acaefda98ae73ccf61413d5044f9f3Chris Craikstatic const UvMapper sIdentity;
2488820fd1d82acaefda98ae73ccf61413d5044f9f3Chris Craik
2493b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guyconst Patch* PatchCache::get(const AssetAtlas::Entry* entry,
2503b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        const uint32_t bitmapWidth, const uint32_t bitmapHeight,
2513b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        const float pixelWidth, const float pixelHeight, const Res_png_9patch* patch) {
2524bb942083a0d4db746adf95349108dd8ef842e32Romain Guy
2533b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    const PatchDescription description(bitmapWidth, bitmapHeight, pixelWidth, pixelHeight, patch);
2543b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    const Patch* mesh = mCache.get(description);
2554bb942083a0d4db746adf95349108dd8ef842e32Romain Guy
2563b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    if (!mesh) {
2578820fd1d82acaefda98ae73ccf61413d5044f9f3Chris Craik        const UvMapper& mapper = entry ? entry->uvMapper : sIdentity;
2588820fd1d82acaefda98ae73ccf61413d5044f9f3Chris Craik        Patch* newMesh = new Patch(bitmapWidth, bitmapHeight,
2598820fd1d82acaefda98ae73ccf61413d5044f9f3Chris Craik                pixelWidth, pixelHeight, mapper, patch);
2602728f961614a385df1f056fc24803a9f65c90fabRomain Guy
2618820fd1d82acaefda98ae73ccf61413d5044f9f3Chris Craik        if (newMesh->vertices) {
2628820fd1d82acaefda98ae73ccf61413d5044f9f3Chris Craik            setupMesh(newMesh);
2632728f961614a385df1f056fc24803a9f65c90fabRomain Guy        }
2642728f961614a385df1f056fc24803a9f65c90fabRomain Guy
265e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy#if DEBUG_PATCHES
266e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        dumpFreeBlocks("Adding patch");
267e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy#endif
268e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy
2693b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        mCache.put(description, newMesh);
2703b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        return newMesh;
271f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy    }
272f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy
273f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy    return mesh;
274f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy}
275f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy
276e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy#if DEBUG_PATCHES
277e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guyvoid PatchCache::dumpFreeBlocks(const char* prefix) {
278e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    String8 dump;
279e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    BufferBlock* block = mFreeBlocks;
280e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    while (block) {
2818820fd1d82acaefda98ae73ccf61413d5044f9f3Chris Craik        dump.appendFormat("->(%d, %d)", block->positionOffset, block->size);
282e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        block = block->next;
283e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    }
284e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    ALOGD("%s: Free blocks%s", prefix, dump.string());
285e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy}
286e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy#endif
287e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy
288f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy}; // namespace uirenderer
289f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy}; // namespace android
290