GradientCache.cpp revision 51d6a3db97bdd5315f1a17a4b447d10a92217b98
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
19059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy#include <utils/JenkinsHash.h>
20a2341a9f6addcd79723965ec5b1a1c5ae0f8bd65Romain Guy
21320d46bf844b84351cb80c5d4a4768d86447ac81Romain Guy#include "Caches.h"
22c9855a53edfac818dc68714557185977556f849dRomain Guy#include "Debug.h"
23c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy#include "GradientCache.h"
24fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy#include "Properties.h"
25c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
26c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guynamespace android {
27c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guynamespace uirenderer {
28c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
29c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy///////////////////////////////////////////////////////////////////////////////
3042e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy// Functions
3142e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy///////////////////////////////////////////////////////////////////////////////
3242e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
3342e1e0d482d774cf18a55773e434f02edb9e4462Romain Guytemplate<typename T>
3442e1e0d482d774cf18a55773e434f02edb9e4462Romain Guystatic inline T min(T a, T b) {
3542e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    return a < b ? a : b;
3642e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy}
3742e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
3842e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy///////////////////////////////////////////////////////////////////////////////
39059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy// Cache entry
40059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy///////////////////////////////////////////////////////////////////////////////
41059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy
42059e12ccd20f5c249724a8362d6bac325334ea76Romain Guyhash_t GradientCacheEntry::hash() const {
43059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    uint32_t hash = JenkinsHashMix(0, count);
44059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    for (uint32_t i = 0; i < count; i++) {
45059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy        hash = JenkinsHashMix(hash, android::hash_type(colors[i]));
46059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy        hash = JenkinsHashMix(hash, android::hash_type(positions[i]));
47059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    }
48059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    return JenkinsHashWhiten(hash);
49059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy}
50059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy
51059e12ccd20f5c249724a8362d6bac325334ea76Romain Guyint GradientCacheEntry::compare(const GradientCacheEntry& lhs, const GradientCacheEntry& rhs) {
52059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    int deltaInt = int(lhs.count) - int(rhs.count);
53059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    if (deltaInt != 0) return deltaInt;
54059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy
5551d6a3db97bdd5315f1a17a4b447d10a92217b98Chris Craik    deltaInt = memcmp(lhs.colors.get(), rhs.colors.get(), lhs.count * sizeof(uint32_t));
56059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    if (deltaInt != 0) return deltaInt;
57059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy
5851d6a3db97bdd5315f1a17a4b447d10a92217b98Chris Craik    return memcmp(lhs.positions.get(), rhs.positions.get(), lhs.count * sizeof(float));
59059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy}
60059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy
61059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy///////////////////////////////////////////////////////////////////////////////
62c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy// Constructors/destructor
63c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy///////////////////////////////////////////////////////////////////////////////
64c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
65fb8b763f762ae21923c58d64caa729b012f40e05Romain GuyGradientCache::GradientCache():
66059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy        mCache(LruCache<GradientCacheEntry, Texture*>::kUnlimitedCapacity),
67fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        mSize(0), mMaxSize(MB(DEFAULT_GRADIENT_CACHE_SIZE)) {
68fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    char property[PROPERTY_VALUE_MAX];
69fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    if (property_get(PROPERTY_GRADIENT_CACHE_SIZE, property, NULL) > 0) {
70c9855a53edfac818dc68714557185977556f849dRomain Guy        INIT_LOGD("  Setting gradient cache size to %sMB", property);
71fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        setMaxSize(MB(atof(property)));
72fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    } else {
73c9855a53edfac818dc68714557185977556f849dRomain Guy        INIT_LOGD("  Using default gradient cache size of %.2fMB", DEFAULT_GRADIENT_CACHE_SIZE);
74fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    }
75fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
76a8557d2169e14997637f57bc897640c8882d4a46Mathias Agopian    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
778dcfd5e836341b4a803b04d104a930bb312182d3Romain Guy
78fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    mCache.setOnEntryRemovedListener(this);
79b48800428906ae455c2b63acacd44e390e1fee49Romain Guy
80b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    const Extensions& extensions = Extensions::getInstance();
817f4307668b10467ee39d41c7ea29cf1ff238a835Romain Guy    mUseFloatTexture = extensions.hasFloatTextures();
82b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    mHasNpot = extensions.hasNPot();
83fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy}
84fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
85c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain GuyGradientCache::GradientCache(uint32_t maxByteSize):
86059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy        mCache(LruCache<GradientCacheEntry, Texture*>::kUnlimitedCapacity),
87c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy        mSize(0), mMaxSize(maxByteSize) {
88c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    mCache.setOnEntryRemovedListener(this);
89c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
90c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
91c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain GuyGradientCache::~GradientCache() {
92c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    mCache.clear();
93c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
94c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
95c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy///////////////////////////////////////////////////////////////////////////////
96c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy// Size management
97c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy///////////////////////////////////////////////////////////////////////////////
98c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
99c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guyuint32_t GradientCache::getSize() {
100c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    return mSize;
101c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
102c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
103c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guyuint32_t GradientCache::getMaxSize() {
104c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    return mMaxSize;
105c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
106c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
107c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guyvoid GradientCache::setMaxSize(uint32_t maxSize) {
108c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    mMaxSize = maxSize;
109c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    while (mSize > mMaxSize) {
110c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy        mCache.removeOldest();
111c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    }
112c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
113c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
114c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy///////////////////////////////////////////////////////////////////////////////
115c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy// Callbacks
116c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy///////////////////////////////////////////////////////////////////////////////
117c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
118e63f7c622a2086aefa80983c6f41b74fb166bb42Chris Craikvoid GradientCache::operator()(GradientCacheEntry&, Texture*& texture) {
1196203f6c8147069976342be8f42add797a50f9557Romain Guy    if (texture) {
120b48800428906ae455c2b63acacd44e390e1fee49Romain Guy        const uint32_t size = texture->width * texture->height * bytesPerPixel();
121c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy        mSize -= size;
122c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
123be1b127c7bec252e0c6ab0e06ed6babed07d496fRomain Guy        texture->deleteTexture();
124c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy        delete texture;
125c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    }
126c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
127c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
128c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy///////////////////////////////////////////////////////////////////////////////
129c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy// Caching
130c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy///////////////////////////////////////////////////////////////////////////////
131c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
13242e1e0d482d774cf18a55773e434f02edb9e4462Romain GuyTexture* GradientCache::get(uint32_t* colors, float* positions, int count) {
13342e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    GradientCacheEntry gradient(colors, positions, count);
1346203f6c8147069976342be8f42add797a50f9557Romain Guy    Texture* texture = mCache.get(gradient);
135c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
1366203f6c8147069976342be8f42add797a50f9557Romain Guy    if (!texture) {
13742e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        texture = addLinearGradient(gradient, colors, positions, count);
138fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy    }
1396203f6c8147069976342be8f42add797a50f9557Romain Guy
1406203f6c8147069976342be8f42add797a50f9557Romain Guy    return texture;
141fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy}
142fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy
143fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guyvoid GradientCache::clear() {
144c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    mCache.clear();
145c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
146c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
14742e1e0d482d774cf18a55773e434f02edb9e4462Romain Guyvoid GradientCache::getGradientInfo(const uint32_t* colors, const int count,
14842e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        GradientInfo& info) {
149320d46bf844b84351cb80c5d4a4768d86447ac81Romain Guy    uint32_t width = 256 * (count - 1);
150320d46bf844b84351cb80c5d4a4768d86447ac81Romain Guy
15195aeff8f11968c8b29ae114bb5e1172c70cf7634Romain Guy    // If the npot extension is not supported we cannot use non-clamp
15295aeff8f11968c8b29ae114bb5e1172c70cf7634Romain Guy    // wrap modes. We therefore find the nearest largest power of 2
15395aeff8f11968c8b29ae114bb5e1172c70cf7634Romain Guy    // unless width is already a power of 2
15495aeff8f11968c8b29ae114bb5e1172c70cf7634Romain Guy    if (!mHasNpot && (width & (width - 1)) != 0) {
15595aeff8f11968c8b29ae114bb5e1172c70cf7634Romain Guy        width = 1 << (32 - __builtin_clz(width));
156320d46bf844b84351cb80c5d4a4768d86447ac81Romain Guy    }
157c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
158320d46bf844b84351cb80c5d4a4768d86447ac81Romain Guy    bool hasAlpha = false;
15942e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    for (int i = 0; i < count; i++) {
16042e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        if (((colors[i] >> 24) & 0xff) < 255) {
16142e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            hasAlpha = true;
16242e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            break;
16342e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        }
16442e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    }
165c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
16642e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    info.width = min(width, uint32_t(mMaxTextureSize));
16742e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    info.hasAlpha = hasAlpha;
16842e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy}
169c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
17042e1e0d482d774cf18a55773e434f02edb9e4462Romain GuyTexture* GradientCache::addLinearGradient(GradientCacheEntry& gradient,
17142e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        uint32_t* colors, float* positions, int count) {
172c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
17342e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    GradientInfo info;
17442e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    getGradientInfo(colors, count, info);
175c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
1768aa195d7081b889f3a7b1f426cbd8556377aae5eRomain Guy    Texture* texture = new Texture();
17742e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    texture->width = info.width;
178b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    texture->height = 2;
17942e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    texture->blend = info.hasAlpha;
18042e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    texture->generation = 1;
181c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
182c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    // Asume the cache is always big enough
183b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    const uint32_t size = texture->width * texture->height * bytesPerPixel();
18415a65bfee5b0a98664eb5ebadad63c73e2c471f8Romain Guy    while (getSize() + size > mMaxSize) {
185c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy        mCache.removeOldest();
186c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    }
187c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
188e63f7c622a2086aefa80983c6f41b74fb166bb42Chris Craik    generateTexture(colors, positions, texture);
189c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
190c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    mSize += size;
1916203f6c8147069976342be8f42add797a50f9557Romain Guy    mCache.put(gradient, texture);
192c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
193c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    return texture;
194c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
195c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
196b48800428906ae455c2b63acacd44e390e1fee49Romain Guysize_t GradientCache::bytesPerPixel() const {
197b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    // We use 4 channels (RGBA)
198b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    return 4 * (mUseFloatTexture ? sizeof(float) : sizeof(uint8_t));
199b48800428906ae455c2b63acacd44e390e1fee49Romain Guy}
200b48800428906ae455c2b63acacd44e390e1fee49Romain Guy
201b48800428906ae455c2b63acacd44e390e1fee49Romain Guyvoid GradientCache::splitToBytes(uint32_t inColor, GradientColor& outColor) const {
202b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    outColor.r = (inColor >> 16) & 0xff;
203b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    outColor.g = (inColor >>  8) & 0xff;
204b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    outColor.b = (inColor >>  0) & 0xff;
205b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    outColor.a = (inColor >> 24) & 0xff;
206b48800428906ae455c2b63acacd44e390e1fee49Romain Guy}
207b48800428906ae455c2b63acacd44e390e1fee49Romain Guy
208b48800428906ae455c2b63acacd44e390e1fee49Romain Guyvoid GradientCache::splitToFloats(uint32_t inColor, GradientColor& outColor) const {
209b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    outColor.r = ((inColor >> 16) & 0xff) / 255.0f;
210b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    outColor.g = ((inColor >>  8) & 0xff) / 255.0f;
211b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    outColor.b = ((inColor >>  0) & 0xff) / 255.0f;
212b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    outColor.a = ((inColor >> 24) & 0xff) / 255.0f;
213b48800428906ae455c2b63acacd44e390e1fee49Romain Guy}
214b48800428906ae455c2b63acacd44e390e1fee49Romain Guy
215b48800428906ae455c2b63acacd44e390e1fee49Romain Guyvoid GradientCache::mixBytes(GradientColor& start, GradientColor& end, float amount,
216b48800428906ae455c2b63acacd44e390e1fee49Romain Guy        uint8_t*& dst) const {
217b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    float oppAmount = 1.0f - amount;
218b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    const float alpha = start.a * oppAmount + end.a * amount;
219b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    const float a = alpha / 255.0f;
220b48800428906ae455c2b63acacd44e390e1fee49Romain Guy
221b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    *dst++ = uint8_t(a * (start.r * oppAmount + end.r * amount));
222b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    *dst++ = uint8_t(a * (start.g * oppAmount + end.g * amount));
223b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    *dst++ = uint8_t(a * (start.b * oppAmount + end.b * amount));
224b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    *dst++ = uint8_t(alpha);
225b48800428906ae455c2b63acacd44e390e1fee49Romain Guy}
226b48800428906ae455c2b63acacd44e390e1fee49Romain Guy
227b48800428906ae455c2b63acacd44e390e1fee49Romain Guyvoid GradientCache::mixFloats(GradientColor& start, GradientColor& end, float amount,
228b48800428906ae455c2b63acacd44e390e1fee49Romain Guy        uint8_t*& dst) const {
229b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    float oppAmount = 1.0f - amount;
230b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    const float a = start.a * oppAmount + end.a * amount;
231b48800428906ae455c2b63acacd44e390e1fee49Romain Guy
232b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    float* d = (float*) dst;
233b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    *d++ = a * (start.r * oppAmount + end.r * amount);
234b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    *d++ = a * (start.g * oppAmount + end.g * amount);
235b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    *d++ = a * (start.b * oppAmount + end.b * amount);
236b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    *d++ = a;
237b48800428906ae455c2b63acacd44e390e1fee49Romain Guy
238b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    dst += 4 * sizeof(float);
239b48800428906ae455c2b63acacd44e390e1fee49Romain Guy}
240b48800428906ae455c2b63acacd44e390e1fee49Romain Guy
241e63f7c622a2086aefa80983c6f41b74fb166bb42Chris Craikvoid GradientCache::generateTexture(uint32_t* colors, float* positions, Texture* texture) {
24242e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    const uint32_t width = texture->width;
243b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    const GLsizei rowBytes = width * bytesPerPixel();
244b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    uint8_t pixels[rowBytes * texture->height];
24542e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
246b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    static ChannelSplitter gSplitters[] = {
247b48800428906ae455c2b63acacd44e390e1fee49Romain Guy            &android::uirenderer::GradientCache::splitToBytes,
248b48800428906ae455c2b63acacd44e390e1fee49Romain Guy            &android::uirenderer::GradientCache::splitToFloats,
249b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    };
250b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    ChannelSplitter split = gSplitters[mUseFloatTexture];
25142e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
252b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    static ChannelMixer gMixers[] = {
253b48800428906ae455c2b63acacd44e390e1fee49Romain Guy            &android::uirenderer::GradientCache::mixBytes,
254b48800428906ae455c2b63acacd44e390e1fee49Romain Guy            &android::uirenderer::GradientCache::mixFloats,
255b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    };
256b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    ChannelMixer mix = gMixers[mUseFloatTexture];
25742e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
258b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    GradientColor start;
259b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    (this->*split)(colors[0], start);
26042e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
261b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    GradientColor end;
262b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    (this->*split)(colors[1], end);
26342e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
264b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    int currentPos = 1;
265b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    float startPos = positions[0];
266b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    float distance = positions[1] - startPos;
267b48800428906ae455c2b63acacd44e390e1fee49Romain Guy
268b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    uint8_t* dst = pixels;
26942e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    for (uint32_t x = 0; x < width; x++) {
27042e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        float pos = x / float(width - 1);
27142e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        if (pos > positions[currentPos]) {
272b48800428906ae455c2b63acacd44e390e1fee49Romain Guy            start = end;
273b48800428906ae455c2b63acacd44e390e1fee49Romain Guy            startPos = positions[currentPos];
27442e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
27542e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            currentPos++;
27642e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
277b48800428906ae455c2b63acacd44e390e1fee49Romain Guy            (this->*split)(colors[currentPos], end);
278b48800428906ae455c2b63acacd44e390e1fee49Romain Guy            distance = positions[currentPos] - startPos;
27942e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        }
28042e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
281b48800428906ae455c2b63acacd44e390e1fee49Romain Guy        float amount = (pos - startPos) / distance;
282b48800428906ae455c2b63acacd44e390e1fee49Romain Guy        (this->*mix)(start, end, amount, dst);
283c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    }
284c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
285b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    memcpy(pixels + rowBytes, pixels, rowBytes);
286c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
287c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    glGenTextures(1, &texture->id);
2888aa195d7081b889f3a7b1f426cbd8556377aae5eRomain Guy    Caches::getInstance().bindTexture(texture->id);
289b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
290c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
291b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    if (mUseFloatTexture) {
292b48800428906ae455c2b63acacd44e390e1fee49Romain Guy        // We have to use GL_RGBA16F because GL_RGBA32F does not support filtering
293b48800428906ae455c2b63acacd44e390e1fee49Romain Guy        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, texture->height, 0,
294b48800428906ae455c2b63acacd44e390e1fee49Romain Guy                GL_RGBA, GL_FLOAT, pixels);
295b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    } else {
296b48800428906ae455c2b63acacd44e390e1fee49Romain Guy        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, texture->height, 0,
297b48800428906ae455c2b63acacd44e390e1fee49Romain Guy                GL_RGBA, GL_UNSIGNED_BYTE, pixels);
298b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    }
299c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
30039d252a6632d057d5077f7eaf1b8ed7a142f3397Romain Guy    texture->setFilter(GL_LINEAR);
30139d252a6632d057d5077f7eaf1b8ed7a142f3397Romain Guy    texture->setWrap(GL_CLAMP_TO_EDGE);
302c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
303c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
304c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}; // namespace uirenderer
305c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}; // namespace android
306