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
19a2341a9f6addcd79723965ec5b1a1c5ae0f8bd65Romain Guy#include <utils/threads.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// Defines
3142e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy///////////////////////////////////////////////////////////////////////////////
3242e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
3342e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy#define GRADIENT_TEXTURE_HEIGHT 2
3442e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy#define GRADIENT_BYTES_PER_PIXEL 4
3542e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
3642e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy///////////////////////////////////////////////////////////////////////////////
3742e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy// Functions
3842e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy///////////////////////////////////////////////////////////////////////////////
3942e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
4042e1e0d482d774cf18a55773e434f02edb9e4462Romain Guytemplate<typename T>
4142e1e0d482d774cf18a55773e434f02edb9e4462Romain Guystatic inline T min(T a, T b) {
4242e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    return a < b ? a : b;
4342e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy}
4442e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
4542e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy///////////////////////////////////////////////////////////////////////////////
46c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy// Constructors/destructor
47c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy///////////////////////////////////////////////////////////////////////////////
48c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
49fb8b763f762ae21923c58d64caa729b012f40e05Romain GuyGradientCache::GradientCache():
506203f6c8147069976342be8f42add797a50f9557Romain Guy        mCache(GenerationCache<GradientCacheEntry, Texture*>::kUnlimitedCapacity),
51fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        mSize(0), mMaxSize(MB(DEFAULT_GRADIENT_CACHE_SIZE)) {
52fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    char property[PROPERTY_VALUE_MAX];
53fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    if (property_get(PROPERTY_GRADIENT_CACHE_SIZE, property, NULL) > 0) {
54c9855a53edfac818dc68714557185977556f849dRomain Guy        INIT_LOGD("  Setting gradient cache size to %sMB", property);
55fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        setMaxSize(MB(atof(property)));
56fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    } else {
57c9855a53edfac818dc68714557185977556f849dRomain Guy        INIT_LOGD("  Using default gradient cache size of %.2fMB", DEFAULT_GRADIENT_CACHE_SIZE);
58fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    }
59fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
60a8557d2169e14997637f57bc897640c8882d4a46Mathias Agopian    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
618dcfd5e836341b4a803b04d104a930bb312182d3Romain Guy
62fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    mCache.setOnEntryRemovedListener(this);
63fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy}
64fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
65c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain GuyGradientCache::GradientCache(uint32_t maxByteSize):
666203f6c8147069976342be8f42add797a50f9557Romain Guy        mCache(GenerationCache<GradientCacheEntry, Texture*>::kUnlimitedCapacity),
67c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy        mSize(0), mMaxSize(maxByteSize) {
68c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    mCache.setOnEntryRemovedListener(this);
69c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
70c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
71c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain GuyGradientCache::~GradientCache() {
72c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    mCache.clear();
73c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
74c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
75c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy///////////////////////////////////////////////////////////////////////////////
76c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy// Size management
77c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy///////////////////////////////////////////////////////////////////////////////
78c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
79c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guyuint32_t GradientCache::getSize() {
80c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    return mSize;
81c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
82c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
83c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guyuint32_t GradientCache::getMaxSize() {
84c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    return mMaxSize;
85c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
86c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
87c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guyvoid GradientCache::setMaxSize(uint32_t maxSize) {
88c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    mMaxSize = maxSize;
89c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    while (mSize > mMaxSize) {
90c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy        mCache.removeOldest();
91c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    }
92c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
93c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
94c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy///////////////////////////////////////////////////////////////////////////////
95c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy// Callbacks
96c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy///////////////////////////////////////////////////////////////////////////////
97c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
986203f6c8147069976342be8f42add797a50f9557Romain Guyvoid GradientCache::operator()(GradientCacheEntry& shader, Texture*& texture) {
996203f6c8147069976342be8f42add797a50f9557Romain Guy    if (texture) {
10042e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        const uint32_t size = texture->width * texture->height * GRADIENT_BYTES_PER_PIXEL;
101c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy        mSize -= size;
102c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    }
103c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
104c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    if (texture) {
105c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy        glDeleteTextures(1, &texture->id);
106c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy        delete texture;
107c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    }
108c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
109c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
110c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy///////////////////////////////////////////////////////////////////////////////
111c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy// Caching
112c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy///////////////////////////////////////////////////////////////////////////////
113c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
11442e1e0d482d774cf18a55773e434f02edb9e4462Romain GuyTexture* GradientCache::get(uint32_t* colors, float* positions, int count) {
115c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
11642e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    GradientCacheEntry gradient(colors, positions, count);
1176203f6c8147069976342be8f42add797a50f9557Romain Guy    Texture* texture = mCache.get(gradient);
118c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
1196203f6c8147069976342be8f42add797a50f9557Romain Guy    if (!texture) {
12042e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        texture = addLinearGradient(gradient, colors, positions, count);
121fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy    }
1226203f6c8147069976342be8f42add797a50f9557Romain Guy
1236203f6c8147069976342be8f42add797a50f9557Romain Guy    return texture;
124fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy}
125fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy
126fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guyvoid GradientCache::clear() {
127c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    mCache.clear();
128c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
129c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
13042e1e0d482d774cf18a55773e434f02edb9e4462Romain Guyvoid GradientCache::getGradientInfo(const uint32_t* colors, const int count,
13142e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        GradientInfo& info) {
132320d46bf844b84351cb80c5d4a4768d86447ac81Romain Guy    uint32_t width = 256 * (count - 1);
133320d46bf844b84351cb80c5d4a4768d86447ac81Romain Guy
134320d46bf844b84351cb80c5d4a4768d86447ac81Romain Guy    if (!Caches::getInstance().extensions.hasNPot()) {
135320d46bf844b84351cb80c5d4a4768d86447ac81Romain Guy        width = 1 << (31 - __builtin_clz(width));
136320d46bf844b84351cb80c5d4a4768d86447ac81Romain Guy    }
137c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
138320d46bf844b84351cb80c5d4a4768d86447ac81Romain Guy    bool hasAlpha = false;
13942e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    for (int i = 0; i < count; i++) {
14042e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        if (((colors[i] >> 24) & 0xff) < 255) {
14142e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            hasAlpha = true;
14242e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            break;
14342e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        }
14442e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    }
145c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
14642e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    info.width = min(width, uint32_t(mMaxTextureSize));
14742e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    info.hasAlpha = hasAlpha;
14842e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy}
149c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
15042e1e0d482d774cf18a55773e434f02edb9e4462Romain GuyTexture* GradientCache::addLinearGradient(GradientCacheEntry& gradient,
15142e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        uint32_t* colors, float* positions, int count) {
152c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
15342e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    GradientInfo info;
15442e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    getGradientInfo(colors, count, info);
155c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
15642e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    Texture* texture = new Texture;
15742e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    texture->width = info.width;
15842e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    texture->height = GRADIENT_TEXTURE_HEIGHT;
15942e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    texture->blend = info.hasAlpha;
16042e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    texture->generation = 1;
161c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
162c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    // Asume the cache is always big enough
16342e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    const uint32_t size = texture->width * texture->height * GRADIENT_BYTES_PER_PIXEL;
164c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    while (mSize + size > mMaxSize) {
165c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy        mCache.removeOldest();
166c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    }
167c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
16842e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    generateTexture(colors, positions, count, texture);
169c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
170c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    mSize += size;
1716203f6c8147069976342be8f42add797a50f9557Romain Guy    mCache.put(gradient, texture);
172c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
173c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    return texture;
174c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
175c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
17642e1e0d482d774cf18a55773e434f02edb9e4462Romain Guyvoid GradientCache::generateTexture(uint32_t* colors, float* positions,
17742e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        int count, Texture* texture) {
17842e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
17942e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    const uint32_t width = texture->width;
18042e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    const GLsizei rowBytes = width * GRADIENT_BYTES_PER_PIXEL;
18142e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    uint32_t pixels[width * texture->height];
18242e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
18342e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    int currentPos = 1;
18442e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
18542e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    float startA = (colors[0] >> 24) & 0xff;
18642e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    float startR = (colors[0] >> 16) & 0xff;
18742e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    float startG = (colors[0] >>  8) & 0xff;
18842e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    float startB = (colors[0] >>  0) & 0xff;
18942e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
19042e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    float endA = (colors[1] >> 24) & 0xff;
19142e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    float endR = (colors[1] >> 16) & 0xff;
19242e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    float endG = (colors[1] >>  8) & 0xff;
19342e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    float endB = (colors[1] >>  0) & 0xff;
19442e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
19542e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    float start = positions[0];
19642e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    float distance = positions[1] - start;
19742e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
19842e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    uint8_t* p = (uint8_t*) pixels;
19942e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    for (uint32_t x = 0; x < width; x++) {
20042e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        float pos = x / float(width - 1);
20142e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        if (pos > positions[currentPos]) {
20242e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            startA = endA;
20342e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            startR = endR;
20442e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            startG = endG;
20542e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            startB = endB;
20642e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            start = positions[currentPos];
20742e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
20842e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            currentPos++;
20942e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
21042e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            endA = (colors[currentPos] >> 24) & 0xff;
21142e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            endR = (colors[currentPos] >> 16) & 0xff;
21242e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            endG = (colors[currentPos] >>  8) & 0xff;
21342e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            endB = (colors[currentPos] >>  0) & 0xff;
21442e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            distance = positions[currentPos] - start;
21542e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        }
21642e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
21742e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        float amount = (pos - start) / distance;
21842e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        float oppAmount = 1.0f - amount;
21942e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
220d679b57ef279239cf11bb6c9bd14fb99b07971c9Romain Guy        const float alpha = startA * oppAmount + endA * amount;
221d679b57ef279239cf11bb6c9bd14fb99b07971c9Romain Guy        const float a = alpha / 255.0f;
222d679b57ef279239cf11bb6c9bd14fb99b07971c9Romain Guy        *p++ = uint8_t(a * (startR * oppAmount + endR * amount));
223d679b57ef279239cf11bb6c9bd14fb99b07971c9Romain Guy        *p++ = uint8_t(a * (startG * oppAmount + endG * amount));
224d679b57ef279239cf11bb6c9bd14fb99b07971c9Romain Guy        *p++ = uint8_t(a * (startB * oppAmount + endB * amount));
225d679b57ef279239cf11bb6c9bd14fb99b07971c9Romain Guy        *p++ = uint8_t(alpha);
226c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    }
227c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
22842e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    for (int i = 1; i < GRADIENT_TEXTURE_HEIGHT; i++) {
22942e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        memcpy(pixels + width * i, pixels, rowBytes);
23042e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    }
231c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
232c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    glGenTextures(1, &texture->id);
233c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
234c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    glBindTexture(GL_TEXTURE_2D, texture->id);
23542e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    glPixelStorei(GL_UNPACK_ALIGNMENT, GRADIENT_BYTES_PER_PIXEL);
236c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
23742e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, texture->height, 0,
23842e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            GL_RGBA, GL_UNSIGNED_BYTE, pixels);
239c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
24039d252a6632d057d5077f7eaf1b8ed7a142f3397Romain Guy    texture->setFilter(GL_LINEAR);
24139d252a6632d057d5077f7eaf1b8ed7a142f3397Romain Guy    texture->setWrap(GL_CLAMP_TO_EDGE);
242c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}
243c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
244c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}; // namespace uirenderer
245c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}; // namespace android
246