TextureCache.cpp revision e9e7fd0813f1485d20c6cd0014d59aff53c35d84
1ce0537b80087a6225273040a987414b1dd081aa0Romain Guy/*
2ce0537b80087a6225273040a987414b1dd081aa0Romain Guy * Copyright (C) 2010 The Android Open Source Project
3ce0537b80087a6225273040a987414b1dd081aa0Romain Guy *
4ce0537b80087a6225273040a987414b1dd081aa0Romain Guy * Licensed under the Apache License, Version 2.0 (the "License");
5ce0537b80087a6225273040a987414b1dd081aa0Romain Guy * you may not use this file except in compliance with the License.
6ce0537b80087a6225273040a987414b1dd081aa0Romain Guy * You may obtain a copy of the License at
7ce0537b80087a6225273040a987414b1dd081aa0Romain Guy *
8ce0537b80087a6225273040a987414b1dd081aa0Romain Guy *      http://www.apache.org/licenses/LICENSE-2.0
9ce0537b80087a6225273040a987414b1dd081aa0Romain Guy *
10ce0537b80087a6225273040a987414b1dd081aa0Romain Guy * Unless required by applicable law or agreed to in writing, software
11ce0537b80087a6225273040a987414b1dd081aa0Romain Guy * distributed under the License is distributed on an "AS IS" BASIS,
12ce0537b80087a6225273040a987414b1dd081aa0Romain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ce0537b80087a6225273040a987414b1dd081aa0Romain Guy * See the License for the specific language governing permissions and
14ce0537b80087a6225273040a987414b1dd081aa0Romain Guy * limitations under the License.
15ce0537b80087a6225273040a987414b1dd081aa0Romain Guy */
16ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
17121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy#define LOG_TAG "OpenGLRenderer"
18121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy
19ce0537b80087a6225273040a987414b1dd081aa0Romain Guy#include <GLES2/gl2.h>
20ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
21ce0537b80087a6225273040a987414b1dd081aa0Romain Guy#include "TextureCache.h"
22ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
23ce0537b80087a6225273040a987414b1dd081aa0Romain Guynamespace android {
24ce0537b80087a6225273040a987414b1dd081aa0Romain Guynamespace uirenderer {
25ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
26121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy///////////////////////////////////////////////////////////////////////////////
27121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy// Constructors/destructor
28121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy///////////////////////////////////////////////////////////////////////////////
29121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy
307d139ba2c331f11e9b485753cc727a0ff202f2a4Romain GuyTextureCache::TextureCache(uint32_t maxByteSize):
316c81893c626499e58c8eeb20d6c35ec4e1ce808bRomain Guy        mCache(GenerationCache<SkBitmap*, Texture*>::kUnlimitedCapacity),
32121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy        mSize(0), mMaxSize(maxByteSize) {
33ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    mCache.setOnEntryRemovedListener(this);
349cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy
35163935113919a184122b8b3bd672ef08c8df65dcRomain Guy    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
36163935113919a184122b8b3bd672ef08c8df65dcRomain Guy    LOGD("Maximum texture dimension is %d pixels", mMaxTextureSize);
37ce0537b80087a6225273040a987414b1dd081aa0Romain Guy}
38ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
39ce0537b80087a6225273040a987414b1dd081aa0Romain GuyTextureCache::~TextureCache() {
40ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    mCache.clear();
41ce0537b80087a6225273040a987414b1dd081aa0Romain Guy}
42ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
43121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy///////////////////////////////////////////////////////////////////////////////
44121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy// Size management
45121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy///////////////////////////////////////////////////////////////////////////////
46121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy
477d139ba2c331f11e9b485753cc727a0ff202f2a4Romain Guyuint32_t TextureCache::getSize() {
48121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy    return mSize;
49121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy}
50121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy
517d139ba2c331f11e9b485753cc727a0ff202f2a4Romain Guyuint32_t TextureCache::getMaxSize() {
52121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy    return mMaxSize;
53121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy}
54121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy
557d139ba2c331f11e9b485753cc727a0ff202f2a4Romain Guyvoid TextureCache::setMaxSize(uint32_t maxSize) {
56121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy    mMaxSize = maxSize;
57121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy    while (mSize > mMaxSize) {
58121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy        mCache.removeOldest();
59121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy    }
60121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy}
61121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy
62121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy///////////////////////////////////////////////////////////////////////////////
63121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy// Callbacks
64121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy///////////////////////////////////////////////////////////////////////////////
65121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy
66dda570201ac851dd85af3861f7e575721d3345daRomain Guyvoid TextureCache::operator()(SkBitmap*& bitmap, Texture*& texture) {
67121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy    if (bitmap) {
687d139ba2c331f11e9b485753cc727a0ff202f2a4Romain Guy        const uint32_t size = bitmap->rowBytes() * bitmap->height();
69121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy        mSize -= size;
70121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy    }
71121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy
72121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy    if (texture) {
73121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy        glDeleteTextures(1, &texture->id);
74121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy        delete texture;
75ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    }
76ce0537b80087a6225273040a987414b1dd081aa0Romain Guy}
77ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
78121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy///////////////////////////////////////////////////////////////////////////////
79121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy// Caching
80121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy///////////////////////////////////////////////////////////////////////////////
81121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy
82ce0537b80087a6225273040a987414b1dd081aa0Romain GuyTexture* TextureCache::get(SkBitmap* bitmap) {
83ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    Texture* texture = mCache.get(bitmap);
84ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    if (!texture) {
859cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy        if (bitmap->width() > mMaxTextureSize || bitmap->height() > mMaxTextureSize) {
869cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy            LOGW("Bitmap too large to be uploaded into a texture");
879cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy            return NULL;
889cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy        }
899cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy
907d139ba2c331f11e9b485753cc727a0ff202f2a4Romain Guy        const uint32_t size = bitmap->rowBytes() * bitmap->height();
91121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy        // Don't even try to cache a bitmap that's bigger than the cache
92121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy        if (size < mMaxSize) {
93121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy            while (mSize + size > mMaxSize) {
94121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy                mCache.removeOldest();
95121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy            }
96121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy        }
97121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy
98364703c6fa4aa1a7d2ef5b0c048ea2a0d57a4c40Romain Guy        texture = new Texture;
99c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guy        generateTexture(bitmap, texture, false);
100121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy
101121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy        if (size < mMaxSize) {
102121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy            mSize += size;
103121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy            mCache.put(bitmap, texture);
10422158e139a3d6c6a9787ca0de224e9368f643284Romain Guy        } else {
10522158e139a3d6c6a9787ca0de224e9368f643284Romain Guy            texture->cleanup = true;
106121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy        }
107fe8809471a40cac8acc984adfa51c39e13e83947Romain Guy    } else if (bitmap->getGenerationID() != texture->generation) {
108fe8809471a40cac8acc984adfa51c39e13e83947Romain Guy        generateTexture(bitmap, texture, true);
109ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    }
11022158e139a3d6c6a9787ca0de224e9368f643284Romain Guy
111ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    return texture;
112ce0537b80087a6225273040a987414b1dd081aa0Romain Guy}
113ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
114121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guyvoid TextureCache::remove(SkBitmap* bitmap) {
115121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy    mCache.remove(bitmap);
116ce0537b80087a6225273040a987414b1dd081aa0Romain Guy}
117ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
118ce0537b80087a6225273040a987414b1dd081aa0Romain Guyvoid TextureCache::clear() {
119ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    mCache.clear();
120ce0537b80087a6225273040a987414b1dd081aa0Romain Guy}
121ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
122fe8809471a40cac8acc984adfa51c39e13e83947Romain Guyvoid TextureCache::generateTexture(SkBitmap* bitmap, Texture* texture, bool regenerate) {
123c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guy    SkAutoLockPixels alp(*bitmap);
124c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guy    if (!bitmap->readyToDraw()) {
125c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guy        LOGE("Cannot generate texture from bitmap");
126c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guy        return;
127c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guy    }
128c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guy
129fe8809471a40cac8acc984adfa51c39e13e83947Romain Guy    if (!regenerate) {
130c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guy        texture->generation = bitmap->getGenerationID();
131fe8809471a40cac8acc984adfa51c39e13e83947Romain Guy        texture->width = bitmap->width();
132fe8809471a40cac8acc984adfa51c39e13e83947Romain Guy        texture->height = bitmap->height();
133fe8809471a40cac8acc984adfa51c39e13e83947Romain Guy
134fe8809471a40cac8acc984adfa51c39e13e83947Romain Guy        glGenTextures(1, &texture->id);
135fe8809471a40cac8acc984adfa51c39e13e83947Romain Guy    }
136ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
137ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    glBindTexture(GL_TEXTURE_2D, texture->id);
138c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guy    glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
139ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
140ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    switch (bitmap->getConfig()) {
141bd0e6aa0ff0bd8b376772c3e23513a6021bdda87Romain Guy    case SkBitmap::kA8_Config:
142bd0e6aa0ff0bd8b376772c3e23513a6021bdda87Romain Guy        texture->blend = true;
143bd0e6aa0ff0bd8b376772c3e23513a6021bdda87Romain Guy        glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, bitmap->rowBytesAsPixels(), texture->height, 0,
144bd0e6aa0ff0bd8b376772c3e23513a6021bdda87Romain Guy                GL_ALPHA, GL_UNSIGNED_BYTE, bitmap->getPixels());
145bd0e6aa0ff0bd8b376772c3e23513a6021bdda87Romain Guy        break;
146ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    case SkBitmap::kRGB_565_Config:
147c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guy        texture->blend = false;
148c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guy        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, bitmap->rowBytesAsPixels(), texture->height, 0,
149c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guy                GL_RGB, GL_UNSIGNED_SHORT_5_6_5, bitmap->getPixels());
150ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        break;
151ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    case SkBitmap::kARGB_8888_Config:
152c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guy        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap->rowBytesAsPixels(), texture->height, 0,
153c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guy                GL_RGBA, GL_UNSIGNED_BYTE, bitmap->getPixels());
154e9e7fd0813f1485d20c6cd0014d59aff53c35d84Romain Guy        // Do this after calling getPixels() to make sure Skia's deferred
155e9e7fd0813f1485d20c6cd0014d59aff53c35d84Romain Guy        // decoding happened
156e9e7fd0813f1485d20c6cd0014d59aff53c35d84Romain Guy        texture->blend = !bitmap->isOpaque();
157ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        break;
158364703c6fa4aa1a7d2ef5b0c048ea2a0d57a4c40Romain Guy    default:
159364703c6fa4aa1a7d2ef5b0c048ea2a0d57a4c40Romain Guy        break;
160ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    }
161ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
162c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guy    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
163c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guy    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1648ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy
165c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guy    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
166c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guy    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
167ce0537b80087a6225273040a987414b1dd081aa0Romain Guy}
168ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
169ce0537b80087a6225273040a987414b1dd081aa0Romain Guy}; // namespace uirenderer
170ce0537b80087a6225273040a987414b1dd081aa0Romain Guy}; // namespace android
171