GradientCache.cpp revision 059e12ccd20f5c249724a8362d6bac325334ea76
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#include <utils/threads.h>
21a2341a9f6addcd79723965ec5b1a1c5ae0f8bd65Romain Guy
22320d46bf844b84351cb80c5d4a4768d86447ac81Romain Guy#include "Caches.h"
23c9855a53edfac818dc68714557185977556f849dRomain Guy#include "Debug.h"
24c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy#include "GradientCache.h"
25fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy#include "Properties.h"
26c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
27c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guynamespace android {
28c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guynamespace uirenderer {
29c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
30c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy///////////////////////////////////////////////////////////////////////////////
3142e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy// Defines
3242e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy///////////////////////////////////////////////////////////////////////////////
3342e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
3442e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy#define GRADIENT_TEXTURE_HEIGHT 2
3542e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy#define GRADIENT_BYTES_PER_PIXEL 4
3642e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
3742e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy///////////////////////////////////////////////////////////////////////////////
3842e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy// Functions
3942e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy///////////////////////////////////////////////////////////////////////////////
4042e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
4142e1e0d482d774cf18a55773e434f02edb9e4462Romain Guytemplate<typename T>
4242e1e0d482d774cf18a55773e434f02edb9e4462Romain Guystatic inline T min(T a, T b) {
4342e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    return a < b ? a : b;
4442e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy}
4542e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
4642e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy///////////////////////////////////////////////////////////////////////////////
47059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy// Cache entry
48059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy///////////////////////////////////////////////////////////////////////////////
49059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy
50059e12ccd20f5c249724a8362d6bac325334ea76Romain Guyhash_t GradientCacheEntry::hash() const {
51059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    uint32_t hash = JenkinsHashMix(0, count);
52059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    hash = JenkinsHashMix(hash, tileMode);
53059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    for (uint32_t i = 0; i < count; i++) {
54059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy        hash = JenkinsHashMix(hash, android::hash_type(colors[i]));
55059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy        hash = JenkinsHashMix(hash, android::hash_type(positions[i]));
56059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    }
57059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    return JenkinsHashWhiten(hash);
58059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy}
59059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy
60059e12ccd20f5c249724a8362d6bac325334ea76Romain Guyint GradientCacheEntry::compare(const GradientCacheEntry& lhs, const GradientCacheEntry& rhs) {
61059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    int deltaInt = int(lhs.count) - int(rhs.count);
62059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    if (deltaInt != 0) return deltaInt;
63059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy
64059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    deltaInt = lhs.tileMode - rhs.tileMode;
65059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    if (deltaInt != 0) return deltaInt;
66059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy
67059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    deltaInt = memcmp(lhs.colors, rhs.colors, lhs.count * sizeof(uint32_t));
68059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    if (deltaInt != 0) return deltaInt;
69059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy
70059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    return memcmp(lhs.positions, rhs.positions, lhs.count * sizeof(float));
71059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy}
72059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy
73059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy///////////////////////////////////////////////////////////////////////////////
74c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy// Constructors/destructor
75c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy///////////////////////////////////////////////////////////////////////////////
76c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
77fb8b763f762ae21923c58d64caa729b012f40e05Romain GuyGradientCache::GradientCache():
78059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy        mCache(LruCache<GradientCacheEntry, Texture*>::kUnlimitedCapacity),
79fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        mSize(0), mMaxSize(MB(DEFAULT_GRADIENT_CACHE_SIZE)) {
80fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    char property[PROPERTY_VALUE_MAX];
81fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    if (property_get(PROPERTY_GRADIENT_CACHE_SIZE, property, NULL) > 0) {
82c9855a53edfac818dc68714557185977556f849dRomain Guy        INIT_LOGD("  Setting gradient cache size to %sMB", property);
83fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        setMaxSize(MB(atof(property)));
84fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    } else {
85c9855a53edfac818dc68714557185977556f849dRomain Guy        INIT_LOGD("  Using default gradient cache size of %.2fMB", DEFAULT_GRADIENT_CACHE_SIZE);
86fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    }
87fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
88a8557d2169e14997637f57bc897640c8882d4a46Mathias Agopian    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
898dcfd5e836341b4a803b04d104a930bb312182d3Romain Guy
90fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    mCache.setOnEntryRemovedListener(this);
91fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy}
92fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
93c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain GuyGradientCache::GradientCache(uint32_t maxByteSize):
94059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy        mCache(LruCache<GradientCacheEntry, Texture*>::kUnlimitedCapacity),
95c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy        mSize(0), mMaxSize(maxByteSize) {
96c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    mCache.setOnEntryRemovedListener(this);
97c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
98c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
99c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain GuyGradientCache::~GradientCache() {
100c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    mCache.clear();
101c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
102c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
103c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy///////////////////////////////////////////////////////////////////////////////
104c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy// Size management
105c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy///////////////////////////////////////////////////////////////////////////////
106c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
107c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guyuint32_t GradientCache::getSize() {
108c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    return mSize;
109c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
110c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
111c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guyuint32_t GradientCache::getMaxSize() {
112c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    return mMaxSize;
113c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
114c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
115c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guyvoid GradientCache::setMaxSize(uint32_t maxSize) {
116c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    mMaxSize = maxSize;
117c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    while (mSize > mMaxSize) {
118c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy        mCache.removeOldest();
119c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    }
120c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
121c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
122c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy///////////////////////////////////////////////////////////////////////////////
123c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy// Callbacks
124c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy///////////////////////////////////////////////////////////////////////////////
125c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
1266203f6c8147069976342be8f42add797a50f9557Romain Guyvoid GradientCache::operator()(GradientCacheEntry& shader, Texture*& texture) {
1276203f6c8147069976342be8f42add797a50f9557Romain Guy    if (texture) {
12842e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        const uint32_t size = texture->width * texture->height * GRADIENT_BYTES_PER_PIXEL;
129c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy        mSize -= size;
130c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    }
131c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
132c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    if (texture) {
133c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy        glDeleteTextures(1, &texture->id);
134c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy        delete texture;
135c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    }
136c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
137c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
138c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy///////////////////////////////////////////////////////////////////////////////
139c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy// Caching
140c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy///////////////////////////////////////////////////////////////////////////////
141c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
14242e1e0d482d774cf18a55773e434f02edb9e4462Romain GuyTexture* GradientCache::get(uint32_t* colors, float* positions, int count) {
143c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
14442e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    GradientCacheEntry gradient(colors, positions, count);
1456203f6c8147069976342be8f42add797a50f9557Romain Guy    Texture* texture = mCache.get(gradient);
146c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
1476203f6c8147069976342be8f42add797a50f9557Romain Guy    if (!texture) {
14842e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        texture = addLinearGradient(gradient, colors, positions, count);
149fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy    }
1506203f6c8147069976342be8f42add797a50f9557Romain Guy
1516203f6c8147069976342be8f42add797a50f9557Romain Guy    return texture;
152fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy}
153fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy
154fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guyvoid GradientCache::clear() {
155c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    mCache.clear();
156c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
157c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
15842e1e0d482d774cf18a55773e434f02edb9e4462Romain Guyvoid GradientCache::getGradientInfo(const uint32_t* colors, const int count,
15942e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        GradientInfo& info) {
160320d46bf844b84351cb80c5d4a4768d86447ac81Romain Guy    uint32_t width = 256 * (count - 1);
161320d46bf844b84351cb80c5d4a4768d86447ac81Romain Guy
162320d46bf844b84351cb80c5d4a4768d86447ac81Romain Guy    if (!Caches::getInstance().extensions.hasNPot()) {
163320d46bf844b84351cb80c5d4a4768d86447ac81Romain Guy        width = 1 << (31 - __builtin_clz(width));
164320d46bf844b84351cb80c5d4a4768d86447ac81Romain Guy    }
165c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
166320d46bf844b84351cb80c5d4a4768d86447ac81Romain Guy    bool hasAlpha = false;
16742e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    for (int i = 0; i < count; i++) {
16842e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        if (((colors[i] >> 24) & 0xff) < 255) {
16942e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            hasAlpha = true;
17042e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            break;
17142e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        }
17242e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    }
173c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
17442e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    info.width = min(width, uint32_t(mMaxTextureSize));
17542e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    info.hasAlpha = hasAlpha;
17642e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy}
177c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
17842e1e0d482d774cf18a55773e434f02edb9e4462Romain GuyTexture* GradientCache::addLinearGradient(GradientCacheEntry& gradient,
17942e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        uint32_t* colors, float* positions, int count) {
180c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
18142e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    GradientInfo info;
18242e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    getGradientInfo(colors, count, info);
183c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
18442e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    Texture* texture = new Texture;
18542e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    texture->width = info.width;
18642e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    texture->height = GRADIENT_TEXTURE_HEIGHT;
18742e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    texture->blend = info.hasAlpha;
18842e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    texture->generation = 1;
189c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
190c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    // Asume the cache is always big enough
19142e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    const uint32_t size = texture->width * texture->height * GRADIENT_BYTES_PER_PIXEL;
192c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    while (mSize + size > mMaxSize) {
193c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy        mCache.removeOldest();
194c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    }
195c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
19642e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    generateTexture(colors, positions, count, texture);
197c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
198c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    mSize += size;
1996203f6c8147069976342be8f42add797a50f9557Romain Guy    mCache.put(gradient, texture);
200c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
201c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    return texture;
202c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
203c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
20442e1e0d482d774cf18a55773e434f02edb9e4462Romain Guyvoid GradientCache::generateTexture(uint32_t* colors, float* positions,
20542e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        int count, Texture* texture) {
20642e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
20742e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    const uint32_t width = texture->width;
20842e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    const GLsizei rowBytes = width * GRADIENT_BYTES_PER_PIXEL;
20942e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    uint32_t pixels[width * texture->height];
21042e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
21142e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    int currentPos = 1;
21242e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
21342e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    float startA = (colors[0] >> 24) & 0xff;
21442e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    float startR = (colors[0] >> 16) & 0xff;
21542e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    float startG = (colors[0] >>  8) & 0xff;
21642e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    float startB = (colors[0] >>  0) & 0xff;
21742e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
21842e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    float endA = (colors[1] >> 24) & 0xff;
21942e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    float endR = (colors[1] >> 16) & 0xff;
22042e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    float endG = (colors[1] >>  8) & 0xff;
22142e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    float endB = (colors[1] >>  0) & 0xff;
22242e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
22342e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    float start = positions[0];
22442e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    float distance = positions[1] - start;
22542e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
22642e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    uint8_t* p = (uint8_t*) pixels;
22742e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    for (uint32_t x = 0; x < width; x++) {
22842e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        float pos = x / float(width - 1);
22942e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        if (pos > positions[currentPos]) {
23042e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            startA = endA;
23142e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            startR = endR;
23242e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            startG = endG;
23342e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            startB = endB;
23442e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            start = positions[currentPos];
23542e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
23642e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            currentPos++;
23742e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
23842e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            endA = (colors[currentPos] >> 24) & 0xff;
23942e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            endR = (colors[currentPos] >> 16) & 0xff;
24042e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            endG = (colors[currentPos] >>  8) & 0xff;
24142e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            endB = (colors[currentPos] >>  0) & 0xff;
24242e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            distance = positions[currentPos] - start;
24342e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        }
24442e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
24542e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        float amount = (pos - start) / distance;
24642e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        float oppAmount = 1.0f - amount;
24742e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
248d679b57ef279239cf11bb6c9bd14fb99b07971c9Romain Guy        const float alpha = startA * oppAmount + endA * amount;
249d679b57ef279239cf11bb6c9bd14fb99b07971c9Romain Guy        const float a = alpha / 255.0f;
250d679b57ef279239cf11bb6c9bd14fb99b07971c9Romain Guy        *p++ = uint8_t(a * (startR * oppAmount + endR * amount));
251d679b57ef279239cf11bb6c9bd14fb99b07971c9Romain Guy        *p++ = uint8_t(a * (startG * oppAmount + endG * amount));
252d679b57ef279239cf11bb6c9bd14fb99b07971c9Romain Guy        *p++ = uint8_t(a * (startB * oppAmount + endB * amount));
253d679b57ef279239cf11bb6c9bd14fb99b07971c9Romain Guy        *p++ = uint8_t(alpha);
254c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    }
255c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
25642e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    for (int i = 1; i < GRADIENT_TEXTURE_HEIGHT; i++) {
25742e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        memcpy(pixels + width * i, pixels, rowBytes);
25842e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    }
259c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
260c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    glGenTextures(1, &texture->id);
261c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
262c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    glBindTexture(GL_TEXTURE_2D, texture->id);
26342e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    glPixelStorei(GL_UNPACK_ALIGNMENT, GRADIENT_BYTES_PER_PIXEL);
264c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
26542e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, texture->height, 0,
26642e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            GL_RGBA, GL_UNSIGNED_BYTE, pixels);
267c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
26839d252a6632d057d5077f7eaf1b8ed7a142f3397Romain Guy    texture->setFilter(GL_LINEAR);
26939d252a6632d057d5077f7eaf1b8ed7a142f3397Romain Guy    texture->setWrap(GL_CLAMP_TO_EDGE);
270c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
271c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
272c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}; // namespace uirenderer
273c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}; // namespace android
274