GradientCache.cpp revision fe48f65922d4a3cc4aefe058cee5acec51504a20
1c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy/* 2c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy * Copyright (C) 2010 The Android Open Source Project 3c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy * 4c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy * Licensed under the Apache License, Version 2.0 (the "License"); 5c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy * you may not use this file except in compliance with the License. 6c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy * You may obtain a copy of the License at 7c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy * 8c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy * http://www.apache.org/licenses/LICENSE-2.0 9c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy * 10c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy * Unless required by applicable law or agreed to in writing, software 11c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy * distributed under the License is distributed on an "AS IS" BASIS, 12c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy * See the License for the specific language governing permissions and 14c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy * limitations under the License. 15c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy */ 16c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 17c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy#define LOG_TAG "OpenGLRenderer" 18c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 19c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy#include <GLES2/gl2.h> 20c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 21c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy#include <SkCanvas.h> 22c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy#include <SkGradientShader.h> 23c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 24a2341a9f6addcd79723965ec5b1a1c5ae0f8bd65Romain Guy#include <utils/threads.h> 25a2341a9f6addcd79723965ec5b1a1c5ae0f8bd65Romain Guy 26c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy#include "GradientCache.h" 27fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy#include "Properties.h" 28c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 29c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guynamespace android { 30c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guynamespace uirenderer { 31c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 32c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy/////////////////////////////////////////////////////////////////////////////// 33c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy// Constructors/destructor 34c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy/////////////////////////////////////////////////////////////////////////////// 35c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 36fb8b763f762ae21923c58d64caa729b012f40e05Romain GuyGradientCache::GradientCache(): 37fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy mCache(GenerationCache<SkShader*, Texture*>::kUnlimitedCapacity), 38fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy mSize(0), mMaxSize(MB(DEFAULT_GRADIENT_CACHE_SIZE)) { 39fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy char property[PROPERTY_VALUE_MAX]; 40fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy if (property_get(PROPERTY_GRADIENT_CACHE_SIZE, property, NULL) > 0) { 41fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy LOGD(" Setting gradient cache size to %sMB", property); 42fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy setMaxSize(MB(atof(property))); 43fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy } else { 44fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy LOGD(" Using default gradient cache size of %.2fMB", DEFAULT_GRADIENT_CACHE_SIZE); 45fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy } 46fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy 47fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy mCache.setOnEntryRemovedListener(this); 48fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy} 49fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy 50c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain GuyGradientCache::GradientCache(uint32_t maxByteSize): 51c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy mCache(GenerationCache<SkShader*, Texture*>::kUnlimitedCapacity), 52c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy mSize(0), mMaxSize(maxByteSize) { 53c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy mCache.setOnEntryRemovedListener(this); 54c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy} 55c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 56c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain GuyGradientCache::~GradientCache() { 57c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy mCache.clear(); 58c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy} 59c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 60c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy/////////////////////////////////////////////////////////////////////////////// 61c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy// Size management 62c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy/////////////////////////////////////////////////////////////////////////////// 63c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 64c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guyuint32_t GradientCache::getSize() { 65c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy return mSize; 66c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy} 67c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 68c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guyuint32_t GradientCache::getMaxSize() { 69c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy return mMaxSize; 70c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy} 71c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 72c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guyvoid GradientCache::setMaxSize(uint32_t maxSize) { 73c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy mMaxSize = maxSize; 74c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy while (mSize > mMaxSize) { 75c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy mCache.removeOldest(); 76c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy } 77c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy} 78c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 79c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy/////////////////////////////////////////////////////////////////////////////// 80c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy// Callbacks 81c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy/////////////////////////////////////////////////////////////////////////////// 82c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 83c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guyvoid GradientCache::operator()(SkShader*& shader, Texture*& texture) { 84a2341a9f6addcd79723965ec5b1a1c5ae0f8bd65Romain Guy // Already locked here 85c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy if (shader) { 86c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy const uint32_t size = texture->width * texture->height * 4; 87c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy mSize -= size; 88c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy } 89c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 90c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy if (texture) { 91c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy glDeleteTextures(1, &texture->id); 92c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy delete texture; 93c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy } 94c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy} 95c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 96c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy/////////////////////////////////////////////////////////////////////////////// 97c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy// Caching 98c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy/////////////////////////////////////////////////////////////////////////////// 99c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 100c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain GuyTexture* GradientCache::get(SkShader* shader) { 1019cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy return mCache.get(shader); 102c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy} 103c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 104c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guyvoid GradientCache::remove(SkShader* shader) { 105c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy mCache.remove(shader); 106c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy} 107c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 108fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guyvoid GradientCache::removeDeferred(SkShader* shader) { 109a2341a9f6addcd79723965ec5b1a1c5ae0f8bd65Romain Guy Mutex::Autolock _l(mLock); 110fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy mGarbage.push(shader); 111fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy} 112fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy 113fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guyvoid GradientCache::clearGarbage() { 114fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy Mutex::Autolock _l(mLock); 115fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy size_t count = mGarbage.size(); 116fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy for (size_t i = 0; i < count; i++) { 117fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy mCache.remove(mGarbage.itemAt(i)); 118fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy } 119fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy mGarbage.clear(); 120fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy} 121fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy 122fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guyvoid GradientCache::clear() { 123c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy mCache.clear(); 124c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy} 125c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 126ee916f14cbd1fe1422c063ce2ef7b185e2bc5c6fRomain GuyTexture* GradientCache::addLinearGradient(SkShader* shader, uint32_t* colors, 127c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy float* positions, int count, SkShader::TileMode tileMode) { 128c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy SkBitmap bitmap; 129c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1024, 1); 130c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy bitmap.allocPixels(); 131c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy bitmap.eraseColor(0); 132c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 133c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy SkCanvas canvas(bitmap); 134c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 135c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy SkPoint points[2]; 136c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy points[0].set(0.0f, 0.0f); 137c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy points[1].set(bitmap.width(), 0.0f); 138c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 139c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy SkShader* localShader = SkGradientShader::CreateLinear(points, 140c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy reinterpret_cast<const SkColor*>(colors), positions, count, tileMode); 141c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 142c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy SkPaint p; 143c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy p.setStyle(SkPaint::kStrokeAndFill_Style); 144c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy p.setShader(localShader)->unref(); 145c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 146c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy canvas.drawRectCoords(0.0f, 0.0f, bitmap.width(), 1.0f, p); 147c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 148c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy // Asume the cache is always big enough 149c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy const uint32_t size = bitmap.rowBytes() * bitmap.height(); 150c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy while (mSize + size > mMaxSize) { 151c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy mCache.removeOldest(); 152c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy } 153c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 154c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy Texture* texture = new Texture; 155c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy generateTexture(&bitmap, texture); 156c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 157c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy mSize += size; 158c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy mCache.put(shader, texture); 159c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 160c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy return texture; 161c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy} 162c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 163c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guyvoid GradientCache::generateTexture(SkBitmap* bitmap, Texture* texture) { 164c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy SkAutoLockPixels autoLock(*bitmap); 165c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy if (!bitmap->readyToDraw()) { 166c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy LOGE("Cannot generate texture from shader"); 167c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy return; 168c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy } 169c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 170c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy texture->generation = bitmap->getGenerationID(); 171c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy texture->width = bitmap->width(); 172c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy texture->height = bitmap->height(); 173c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 174c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy glGenTextures(1, &texture->id); 175c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 176c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy glBindTexture(GL_TEXTURE_2D, texture->id); 177c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel()); 178c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 179c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy texture->blend = !bitmap->isOpaque(); 180c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap->rowBytesAsPixels(), texture->height, 0, 181c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy GL_RGBA, GL_UNSIGNED_BYTE, bitmap->getPixels()); 182c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 183c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 184c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 185c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 186c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 187c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 188c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy} 189c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy 190c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}; // namespace uirenderer 191c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}; // namespace android 192