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
175b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy#ifndef ANDROID_HWUI_GRADIENT_CACHE_H
185b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy#define ANDROID_HWUI_GRADIENT_CACHE_H
19c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
2096a5c4c7bab6718524de7253da8309143ab48befChris Craik#include <memory>
2196a5c4c7bab6718524de7253da8309143ab48befChris Craik
22b48800428906ae455c2b63acacd44e390e1fee49Romain Guy#include <GLES3/gl3.h>
238dcfd5e836341b4a803b04d104a930bb312182d3Romain Guy
24c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy#include <SkShader.h>
25c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
26059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy#include <utils/LruCache.h>
27029f64303b8fe506ef34c12777da86b830d3bf7aDerek Sollenberger#include <utils/Mutex.h>
28fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy
29253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy#include "FloatColor.h"
30253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy
31c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guynamespace android {
32c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guynamespace uirenderer {
33c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
342dc236b2bae13b9a0ed9b3f7320502aecd7983b3Tom Hudsonclass Texture;
352dc236b2bae13b9a0ed9b3f7320502aecd7983b3Tom Hudson
366203f6c8147069976342be8f42add797a50f9557Romain Guystruct GradientCacheEntry {
376203f6c8147069976342be8f42add797a50f9557Romain Guy    GradientCacheEntry() {
386203f6c8147069976342be8f42add797a50f9557Romain Guy        count = 0;
39e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik        colors = nullptr;
40e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik        positions = nullptr;
416203f6c8147069976342be8f42add797a50f9557Romain Guy    }
426203f6c8147069976342be8f42add797a50f9557Romain Guy
43059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    GradientCacheEntry(uint32_t* colors, float* positions, uint32_t count) {
4442e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        copy(colors, positions, count);
456203f6c8147069976342be8f42add797a50f9557Romain Guy    }
466203f6c8147069976342be8f42add797a50f9557Romain Guy
476203f6c8147069976342be8f42add797a50f9557Romain Guy    GradientCacheEntry(const GradientCacheEntry& entry) {
4851d6a3db97bdd5315f1a17a4b447d10a92217b98Chris Craik        copy(entry.colors.get(), entry.positions.get(), entry.count);
49e5df231434357424cea8d2b8d0cdf31253a98110Romain Guy    }
50e5df231434357424cea8d2b8d0cdf31253a98110Romain Guy
51e5df231434357424cea8d2b8d0cdf31253a98110Romain Guy    GradientCacheEntry& operator=(const GradientCacheEntry& entry) {
52e5df231434357424cea8d2b8d0cdf31253a98110Romain Guy        if (this != &entry) {
5351d6a3db97bdd5315f1a17a4b447d10a92217b98Chris Craik            copy(entry.colors.get(), entry.positions.get(), entry.count);
54e5df231434357424cea8d2b8d0cdf31253a98110Romain Guy        }
55e5df231434357424cea8d2b8d0cdf31253a98110Romain Guy
56e5df231434357424cea8d2b8d0cdf31253a98110Romain Guy        return *this;
576203f6c8147069976342be8f42add797a50f9557Romain Guy    }
586203f6c8147069976342be8f42add797a50f9557Romain Guy
59059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    hash_t hash() const;
60059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy
61059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    static int compare(const GradientCacheEntry& lhs, const GradientCacheEntry& rhs);
62059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy
63059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    bool operator==(const GradientCacheEntry& other) const {
64059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy        return compare(*this, other) == 0;
65059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    }
66059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy
67059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    bool operator!=(const GradientCacheEntry& other) const {
68059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy        return compare(*this, other) != 0;
696203f6c8147069976342be8f42add797a50f9557Romain Guy    }
706203f6c8147069976342be8f42add797a50f9557Romain Guy
7151d6a3db97bdd5315f1a17a4b447d10a92217b98Chris Craik    std::unique_ptr<uint32_t[]> colors;
7251d6a3db97bdd5315f1a17a4b447d10a92217b98Chris Craik    std::unique_ptr<float[]> positions;
73059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    uint32_t count;
746203f6c8147069976342be8f42add797a50f9557Romain Guy
75e5df231434357424cea8d2b8d0cdf31253a98110Romain Guyprivate:
76059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    void copy(uint32_t* colors, float* positions, uint32_t count) {
77e5df231434357424cea8d2b8d0cdf31253a98110Romain Guy        this->count = count;
7851d6a3db97bdd5315f1a17a4b447d10a92217b98Chris Craik        this->colors.reset(new uint32_t[count]);
7951d6a3db97bdd5315f1a17a4b447d10a92217b98Chris Craik        this->positions.reset(new float[count]);
80e5df231434357424cea8d2b8d0cdf31253a98110Romain Guy
8151d6a3db97bdd5315f1a17a4b447d10a92217b98Chris Craik        memcpy(this->colors.get(), colors, count * sizeof(uint32_t));
8251d6a3db97bdd5315f1a17a4b447d10a92217b98Chris Craik        memcpy(this->positions.get(), positions, count * sizeof(float));
83e5df231434357424cea8d2b8d0cdf31253a98110Romain Guy    }
84e5df231434357424cea8d2b8d0cdf31253a98110Romain Guy
856203f6c8147069976342be8f42add797a50f9557Romain Guy}; // GradientCacheEntry
866203f6c8147069976342be8f42add797a50f9557Romain Guy
87059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy// Caching support
88059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy
89059e12ccd20f5c249724a8362d6bac325334ea76Romain Guyinline int strictly_order_type(const GradientCacheEntry& lhs, const GradientCacheEntry& rhs) {
90059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    return GradientCacheEntry::compare(lhs, rhs) < 0;
91059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy}
92059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy
93059e12ccd20f5c249724a8362d6bac325334ea76Romain Guyinline int compare_type(const GradientCacheEntry& lhs, const GradientCacheEntry& rhs) {
94059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    return GradientCacheEntry::compare(lhs, rhs);
95059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy}
96059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy
97059e12ccd20f5c249724a8362d6bac325334ea76Romain Guyinline hash_t hash_type(const GradientCacheEntry& entry) {
98059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    return entry.hash();
99059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy}
100059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy
101c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy/**
102c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy * A simple LRU gradient cache. The cache has a maximum size expressed in bytes.
103c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy * Any texture added to the cache causing the cache to grow beyond the maximum
104c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy * allowed size will also cause the oldest texture to be kicked out.
105c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy */
1066203f6c8147069976342be8f42add797a50f9557Romain Guyclass GradientCache: public OnEntryRemoved<GradientCacheEntry, Texture*> {
107c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guypublic:
108faecb78a6b11c780db47bc940ca7662899ab5d5eChih-Hung Hsieh    explicit GradientCache(Extensions& extensions);
109c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    ~GradientCache();
110c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
111c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    /**
112c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy     * Used as a callback when an entry is removed from the cache.
113c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy     * Do not invoke directly.
114c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy     */
115e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    void operator()(GradientCacheEntry& shader, Texture*& texture) override;
116c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
117c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    /**
118c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy     * Returns the texture associated with the specified shader.
119c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy     */
12042e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    Texture* get(uint32_t* colors, float* positions, int count);
12142e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
122fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy    /**
123c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy     * Clears the cache. This causes all textures to be deleted.
124c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy     */
125c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    void clear();
126c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
127c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    /**
128c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy     * Returns the maximum size of the cache in bytes.
129c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy     */
130c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    uint32_t getMaxSize();
131c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    /**
132c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy     * Returns the current size of the cache in bytes.
133c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy     */
134c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    uint32_t getSize();
135c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
136c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guyprivate:
1376203f6c8147069976342be8f42add797a50f9557Romain Guy    /**
1386203f6c8147069976342be8f42add797a50f9557Romain Guy     * Adds a new linear gradient to the cache. The generated texture is
1396203f6c8147069976342be8f42add797a50f9557Romain Guy     * returned.
1406203f6c8147069976342be8f42add797a50f9557Romain Guy     */
1416203f6c8147069976342be8f42add797a50f9557Romain Guy    Texture* addLinearGradient(GradientCacheEntry& gradient,
14242e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy            uint32_t* colors, float* positions, int count);
14342e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
14438e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    void generateTexture(uint32_t* colors, float* positions,
14538e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck            const uint32_t width, const uint32_t height, Texture* texture);
14642e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy
14742e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    struct GradientInfo {
14842e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        uint32_t width;
14942e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy        bool hasAlpha;
15042e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    };
1516203f6c8147069976342be8f42add797a50f9557Romain Guy
15242e1e0d482d774cf18a55773e434f02edb9e4462Romain Guy    void getGradientInfo(const uint32_t* colors, const int count, GradientInfo& info);
153c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
154b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    size_t bytesPerPixel() const;
155253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy    size_t sourceBytesPerPixel() const;
156b48800428906ae455c2b63acacd44e390e1fee49Romain Guy
1578762e332e3797fb41929a1c6069207f4906ca329Romain Guy    typedef void (GradientCache::*ChannelMixer)(const FloatColor& start, const FloatColor& end,
158b48800428906ae455c2b63acacd44e390e1fee49Romain Guy            float amount, uint8_t*& dst) const;
159b48800428906ae455c2b63acacd44e390e1fee49Romain Guy
1608762e332e3797fb41929a1c6069207f4906ca329Romain Guy    void mixBytes(const FloatColor& start, const FloatColor& end,
1618762e332e3797fb41929a1c6069207f4906ca329Romain Guy            float amount, uint8_t*& dst) const;
1628762e332e3797fb41929a1c6069207f4906ca329Romain Guy    void mixFloats(const FloatColor& start, const FloatColor& end,
1638762e332e3797fb41929a1c6069207f4906ca329Romain Guy            float amount, uint8_t*& dst) const;
164b48800428906ae455c2b63acacd44e390e1fee49Romain Guy
165059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    LruCache<GradientCacheEntry, Texture*> mCache;
166c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
167c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    uint32_t mSize;
16848a8f431fa52ae2ee25ffba9d20676f03bb710ffChris Craik    const uint32_t mMaxSize;
169a2341a9f6addcd79723965ec5b1a1c5ae0f8bd65Romain Guy
1708dcfd5e836341b4a803b04d104a930bb312182d3Romain Guy    GLint mMaxTextureSize;
171b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    bool mUseFloatTexture;
172b48800428906ae455c2b63acacd44e390e1fee49Romain Guy    bool mHasNpot;
173efb4b06493fe7b1604c762a448b13c7af2845a8dRomain Guy    bool mHasLinearBlending;
1748dcfd5e836341b4a803b04d104a930bb312182d3Romain Guy
175a2341a9f6addcd79723965ec5b1a1c5ae0f8bd65Romain Guy    mutable Mutex mLock;
176c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}; // class GradientCache
177c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
178c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}; // namespace uirenderer
179c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy}; // namespace android
180c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
1815b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy#endif // ANDROID_HWUI_GRADIENT_CACHE_H
182