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
17059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy#include <utils/JenkinsHash.h>
18a2341a9f6addcd79723965ec5b1a1c5ae0f8bd65Romain Guy
19320d46bf844b84351cb80c5d4a4768d86447ac81Romain Guy#include "Caches.h"
20c9855a53edfac818dc68714557185977556f849dRomain Guy#include "Debug.h"
21c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy#include "GradientCache.h"
22fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy#include "Properties.h"
23c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
246b50780363d3bb8db600c770183fa07677509ae8John Reck#include <cutils/properties.h>
256b50780363d3bb8db600c770183fa07677509ae8John Reck
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
65117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris CraikGradientCache::GradientCache(Extensions& extensions)
66117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        : mCache(LruCache<GradientCacheEntry, Texture*>::kUnlimitedCapacity)
67117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        , mSize(0)
6848a8f431fa52ae2ee25ffba9d20676f03bb710ffChris Craik        , mMaxSize(Properties::gradientCacheSize)
69117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        , mUseFloatTexture(extensions.hasFloatTextures())
70253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy        , mHasNpot(extensions.hasNPot())
71efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy        , mHasLinearBlending(extensions.hasLinearBlending()) {
72a8557d2169e14997637f57bc897640c8882d4a46Mathias Agopian    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
738dcfd5e836341b4a803b04d104a930bb312182d3Romain Guy
74fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    mCache.setOnEntryRemovedListener(this);
75c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
76c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
77c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain GuyGradientCache::~GradientCache() {
78c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    mCache.clear();
79c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
80c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
81c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy///////////////////////////////////////////////////////////////////////////////
82c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy// Size management
83c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy///////////////////////////////////////////////////////////////////////////////
84c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
85c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guyuint32_t GradientCache::getSize() {
86c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    return mSize;
87c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
88c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
89c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guyuint32_t GradientCache::getMaxSize() {
90c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    return mMaxSize;
91c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
92c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
93c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy///////////////////////////////////////////////////////////////////////////////
94c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy// Callbacks
95c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy///////////////////////////////////////////////////////////////////////////////
96c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
97e63f7c622a2086aefa80983c6f41b74fb166bb42Chris Craikvoid GradientCache::operator()(GradientCacheEntry&, Texture*& texture) {
986203f6c8147069976342be8f42add797a50f9557Romain Guy    if (texture) {
9938e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck        mSize -= texture->objectSize();
100be1b127c7bec252e0c6ab0e06ed6babed07d496fRomain Guy        texture->deleteTexture();
101c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy        delete texture;
102c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    }
103c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
104c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
105c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy///////////////////////////////////////////////////////////////////////////////
106c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy// Caching
107c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy///////////////////////////////////////////////////////////////////////////////
108c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
10942e1e0d482d774cf18a55773e434f02edb9e4462Romain GuyTexture* GradientCache::get(uint32_t* colors, float* positions, int count) {
11042e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    GradientCacheEntry gradient(colors, positions, count);
1116203f6c8147069976342be8f42add797a50f9557Romain Guy    Texture* texture = mCache.get(gradient);
112c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
1136203f6c8147069976342be8f42add797a50f9557Romain Guy    if (!texture) {
11442e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        texture = addLinearGradient(gradient, colors, positions, count);
115fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy    }
1166203f6c8147069976342be8f42add797a50f9557Romain Guy
1176203f6c8147069976342be8f42add797a50f9557Romain Guy    return texture;
118fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy}
119fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy
120fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guyvoid GradientCache::clear() {
121c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    mCache.clear();
122c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
123c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
12442e1e0d482d774cf18a55773e434f02edb9e4462Romain Guyvoid GradientCache::getGradientInfo(const uint32_t* colors, const int count,
12542e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        GradientInfo& info) {
126320d46bf844b84351cb80c5d4a4768d86447ac81Romain Guy    uint32_t width = 256 * (count - 1);
127320d46bf844b84351cb80c5d4a4768d86447ac81Romain Guy
12895aeff8f11968c8b29ae114bb5e1172c70cf7634Romain Guy    // If the npot extension is not supported we cannot use non-clamp
12995aeff8f11968c8b29ae114bb5e1172c70cf7634Romain Guy    // wrap modes. We therefore find the nearest largest power of 2
13095aeff8f11968c8b29ae114bb5e1172c70cf7634Romain Guy    // unless width is already a power of 2
13195aeff8f11968c8b29ae114bb5e1172c70cf7634Romain Guy    if (!mHasNpot && (width & (width - 1)) != 0) {
13295aeff8f11968c8b29ae114bb5e1172c70cf7634Romain Guy        width = 1 << (32 - __builtin_clz(width));
133320d46bf844b84351cb80c5d4a4768d86447ac81Romain Guy    }
134c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
135320d46bf844b84351cb80c5d4a4768d86447ac81Romain Guy    bool hasAlpha = false;
13642e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    for (int i = 0; i < count; i++) {
13742e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        if (((colors[i] >> 24) & 0xff) < 255) {
13842e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            hasAlpha = true;
13942e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            break;
14042e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        }
14142e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    }
142c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
14342e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    info.width = min(width, uint32_t(mMaxTextureSize));
14442e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    info.hasAlpha = hasAlpha;
14542e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy}
146c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
14742e1e0d482d774cf18a55773e434f02edb9e4462Romain GuyTexture* GradientCache::addLinearGradient(GradientCacheEntry& gradient,
14842e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        uint32_t* colors, float* positions, int count) {
149c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
15042e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    GradientInfo info;
15142e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    getGradientInfo(colors, count, info);
152c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
1538e93a7c9377b4ae43ecfb408f4906a09f6c83c03Chris Craik    Texture* texture = new Texture(Caches::getInstance());
15442e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    texture->blend = info.hasAlpha;
15542e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    texture->generation = 1;
156c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
15783c9b5bf638d75a3395f57c2c57c31c959632f9dJohn Reck    // Assume the cache is always big enough
15838e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    const uint32_t size = info.width * 2 * bytesPerPixel();
15915a65bfee5b0a98664eb5ebadad63c73e2c471f8Romain Guy    while (getSize() + size > mMaxSize) {
16083c9b5bf638d75a3395f57c2c57c31c959632f9dJohn Reck        LOG_ALWAYS_FATAL_IF(!mCache.removeOldest(),
16183c9b5bf638d75a3395f57c2c57c31c959632f9dJohn Reck                "Ran out of things to remove from the cache? getSize() = %" PRIu32
16283c9b5bf638d75a3395f57c2c57c31c959632f9dJohn Reck                ", size = %" PRIu32 ", mMaxSize = %" PRIu32 ", width = %" PRIu32,
16383c9b5bf638d75a3395f57c2c57c31c959632f9dJohn Reck                getSize(), size, mMaxSize, info.width);
164c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    }
165c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
16638e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    generateTexture(colors, positions, info.width, 2, texture);
167c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
168c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    mSize += size;
1691d4e6a0901e5d26f4319ed173b4aa7b907350d93John Reck    LOG_ALWAYS_FATAL_IF((int)size != texture->objectSize(),
170d61fd4ede537695d6f7c340aae365095e5bade4dJohn Reck            "size != texture->objectSize(), size %" PRIu32 ", objectSize %d"
171d61fd4ede537695d6f7c340aae365095e5bade4dJohn Reck            " width = %" PRIu32 " bytesPerPixel() = %zu",
1721d4e6a0901e5d26f4319ed173b4aa7b907350d93John Reck            size, texture->objectSize(), info.width, bytesPerPixel());
1736203f6c8147069976342be8f42add797a50f9557Romain Guy    mCache.put(gradient, texture);
174c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
175c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    return texture;
176c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
177c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
178b48800428906ae455c2b63acacd44e390e1fee49Romain Guysize_t GradientCache::bytesPerPixel() const {
179b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    // We use 4 channels (RGBA)
180253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy    return 4 * (mUseFloatTexture ? /* fp16 */ 2 : sizeof(uint8_t));
181b48800428906ae455c2b63acacd44e390e1fee49Romain Guy}
182b48800428906ae455c2b63acacd44e390e1fee49Romain Guy
183253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guysize_t GradientCache::sourceBytesPerPixel() const {
184253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy    // We use 4 channels (RGBA) and upload from floats (not half floats)
185253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy    return 4 * (mUseFloatTexture ? sizeof(float) : sizeof(uint8_t));
186b48800428906ae455c2b63acacd44e390e1fee49Romain Guy}
187b48800428906ae455c2b63acacd44e390e1fee49Romain Guy
1888762e332e3797fb41929a1c6069207f4906ca329Romain Guyvoid GradientCache::mixBytes(const FloatColor& start, const FloatColor& end,
1898762e332e3797fb41929a1c6069207f4906ca329Romain Guy        float amount, uint8_t*& dst) const {
190b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    float oppAmount = 1.0f - amount;
191a0ed6f03f6f06eb41cbcc15c0a99b4a78fd91befRomain Guy    float a = start.a * oppAmount + end.a * amount;
192669b15a93548b82135c73196665bcb7f03d87795Derek Sollenberger    *dst++ = uint8_t(OECF(start.r * oppAmount + end.r * amount) * 255.0f);
193669b15a93548b82135c73196665bcb7f03d87795Derek Sollenberger    *dst++ = uint8_t(OECF(start.g * oppAmount + end.g * amount) * 255.0f);
194669b15a93548b82135c73196665bcb7f03d87795Derek Sollenberger    *dst++ = uint8_t(OECF(start.b * oppAmount + end.b * amount) * 255.0f);
195a0ed6f03f6f06eb41cbcc15c0a99b4a78fd91befRomain Guy    *dst++ = uint8_t(a * 255.0f);
196b48800428906ae455c2b63acacd44e390e1fee49Romain Guy}
197b48800428906ae455c2b63acacd44e390e1fee49Romain Guy
1988762e332e3797fb41929a1c6069207f4906ca329Romain Guyvoid GradientCache::mixFloats(const FloatColor& start, const FloatColor& end,
1998762e332e3797fb41929a1c6069207f4906ca329Romain Guy        float amount, uint8_t*& dst) const {
200b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    float oppAmount = 1.0f - amount;
201a0ed6f03f6f06eb41cbcc15c0a99b4a78fd91befRomain Guy    float a = start.a * oppAmount + end.a * amount;
202b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    float* d = (float*) dst;
203f9037dabea3ccf80b05ec1d66aeac13bee38b239Romain Guy#ifdef ANDROID_ENABLE_LINEAR_BLENDING
2046183c97e5f317ad52ad16fe50e40129e2c7b2150Romain Guy    // We want to stay linear
205669b15a93548b82135c73196665bcb7f03d87795Derek Sollenberger    *d++ = (start.r * oppAmount + end.r * amount);
206669b15a93548b82135c73196665bcb7f03d87795Derek Sollenberger    *d++ = (start.g * oppAmount + end.g * amount);
207669b15a93548b82135c73196665bcb7f03d87795Derek Sollenberger    *d++ = (start.b * oppAmount + end.b * amount);
2088762e332e3797fb41929a1c6069207f4906ca329Romain Guy#else
209669b15a93548b82135c73196665bcb7f03d87795Derek Sollenberger    *d++ = OECF(start.r * oppAmount + end.r * amount);
210669b15a93548b82135c73196665bcb7f03d87795Derek Sollenberger    *d++ = OECF(start.g * oppAmount + end.g * amount);
211669b15a93548b82135c73196665bcb7f03d87795Derek Sollenberger    *d++ = OECF(start.b * oppAmount + end.b * amount);
2128762e332e3797fb41929a1c6069207f4906ca329Romain Guy#endif
213a0ed6f03f6f06eb41cbcc15c0a99b4a78fd91befRomain Guy    *d++ = a;
214b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    dst += 4 * sizeof(float);
215b48800428906ae455c2b63acacd44e390e1fee49Romain Guy}
216b48800428906ae455c2b63acacd44e390e1fee49Romain Guy
21738e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reckvoid GradientCache::generateTexture(uint32_t* colors, float* positions,
21838e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck        const uint32_t width, const uint32_t height, Texture* texture) {
219253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy    const GLsizei rowBytes = width * sourceBytesPerPixel();
22038e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    uint8_t pixels[rowBytes * height];
22142e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
222b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    static ChannelMixer gMixers[] = {
223a0ed6f03f6f06eb41cbcc15c0a99b4a78fd91befRomain Guy            // colors are stored gamma-encoded
224a0ed6f03f6f06eb41cbcc15c0a99b4a78fd91befRomain Guy            &android::uirenderer::GradientCache::mixBytes,
225a0ed6f03f6f06eb41cbcc15c0a99b4a78fd91befRomain Guy            // colors are stored in linear (linear blending on)
226a0ed6f03f6f06eb41cbcc15c0a99b4a78fd91befRomain Guy            // or gamma-encoded (linear blending off)
227a0ed6f03f6f06eb41cbcc15c0a99b4a78fd91befRomain Guy            &android::uirenderer::GradientCache::mixFloats,
228b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    };
229b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    ChannelMixer mix = gMixers[mUseFloatTexture];
23042e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
231253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy    FloatColor start;
232669b15a93548b82135c73196665bcb7f03d87795Derek Sollenberger    start.set(colors[0]);
23342e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
234253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy    FloatColor end;
235669b15a93548b82135c73196665bcb7f03d87795Derek Sollenberger    end.set(colors[1]);
23642e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
237b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    int currentPos = 1;
238b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    float startPos = positions[0];
239b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    float distance = positions[1] - startPos;
240b48800428906ae455c2b63acacd44e390e1fee49Romain Guy
241b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    uint8_t* dst = pixels;
24242e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    for (uint32_t x = 0; x < width; x++) {
24342e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        float pos = x / float(width - 1);
24442e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        if (pos > positions[currentPos]) {
245b48800428906ae455c2b63acacd44e390e1fee49Romain Guy            start = end;
246b48800428906ae455c2b63acacd44e390e1fee49Romain Guy            startPos = positions[currentPos];
24742e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
24842e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            currentPos++;
24942e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
250669b15a93548b82135c73196665bcb7f03d87795Derek Sollenberger            end.set(colors[currentPos]);
251b48800428906ae455c2b63acacd44e390e1fee49Romain Guy            distance = positions[currentPos] - startPos;
25242e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        }
25342e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
254b48800428906ae455c2b63acacd44e390e1fee49Romain Guy        float amount = (pos - startPos) / distance;
255b48800428906ae455c2b63acacd44e390e1fee49Romain Guy        (this->*mix)(start, end, amount, dst);
256c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    }
257c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
258b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    memcpy(pixels + rowBytes, pixels, rowBytes);
259c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
260b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    if (mUseFloatTexture) {
2619372ac3621848085e77b867f220c0b5ffce4010dJohn Reck        texture->upload(GL_RGBA16F, width, height, GL_RGBA, GL_FLOAT, pixels);
262b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    } else {
263efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy        GLint internalFormat = mHasLinearBlending ? GL_SRGB8_ALPHA8 : GL_RGBA;
264253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy        texture->upload(internalFormat, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
265b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    }
266c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
26739d252a6632d057d5077f7eaf1b8ed7a142f3397Romain Guy    texture->setFilter(GL_LINEAR);
26839d252a6632d057d5077f7eaf1b8ed7a142f3397Romain Guy    texture->setWrap(GL_CLAMP_TO_EDGE);
269c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
270c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
271c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}; // namespace uirenderer
272c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}; // namespace android
273