ProgramCache.h revision dbc26d2ba13f80a7590c57de2d80530d96832969
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ANDROID_UI_PROGRAM_CACHE_H
18#define ANDROID_UI_PROGRAM_CACHE_H
19
20#include <utils/KeyedVector.h>
21#include <utils/Log.h>
22#include <utils/String8.h>
23
24#include <GLES2/gl2.h>
25
26#include <SkXfermode.h>
27
28#include "Program.h"
29
30namespace android {
31namespace uirenderer {
32
33///////////////////////////////////////////////////////////////////////////////
34// Defines
35///////////////////////////////////////////////////////////////////////////////
36
37// Debug
38#define DEBUG_PROGRAM_CACHE 0
39
40// Debug
41#if DEBUG_PROGRAM_CACHE
42    #define PROGRAM_LOGD(...) LOGD(__VA_ARGS__)
43#else
44    #define PROGRAM_LOGD(...)
45#endif
46
47// TODO: This should be set in properties
48#define PANEL_BIT_DEPTH 20
49#define COLOR_COMPONENT_THRESHOLD (1.0f - (0.5f / PANEL_BIT_DEPTH))
50#define COLOR_COMPONENT_INV_THRESHOLD (0.5f / PANEL_BIT_DEPTH)
51
52#define PROGRAM_KEY_TEXTURE 0x1
53#define PROGRAM_KEY_A8_TEXTURE 0x2
54#define PROGRAM_KEY_BITMAP 0x4
55#define PROGRAM_KEY_GRADIENT 0x8
56#define PROGRAM_KEY_BITMAP_FIRST 0x10
57#define PROGRAM_KEY_COLOR_MATRIX 0x20
58#define PROGRAM_KEY_COLOR_LIGHTING 0x40
59#define PROGRAM_KEY_COLOR_BLEND 0x80
60#define PROGRAM_KEY_BITMAP_NPOT 0x100
61#define PROGRAM_KEY_SWAP_SRC_DST 0x2000
62
63#define PROGRAM_KEY_BITMAP_WRAPS_MASK 0x600
64#define PROGRAM_KEY_BITMAP_WRAPT_MASK 0x1800
65
66// Encode the xfermodes on 6 bits
67#define PROGRAM_MAX_XFERMODE 0x1f
68#define PROGRAM_XFERMODE_SHADER_SHIFT 26
69#define PROGRAM_XFERMODE_COLOR_OP_SHIFT 20
70#define PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT 14
71
72#define PROGRAM_BITMAP_WRAPS_SHIFT 9
73#define PROGRAM_BITMAP_WRAPT_SHIFT 11
74
75#define PROGRAM_GRADIENT_TYPE_SHIFT 33
76#define PROGRAM_MODULATE 35
77
78///////////////////////////////////////////////////////////////////////////////
79// Types
80///////////////////////////////////////////////////////////////////////////////
81
82typedef uint64_t programid;
83
84///////////////////////////////////////////////////////////////////////////////
85// Cache
86///////////////////////////////////////////////////////////////////////////////
87
88/**
89 * Describe the features required for a given program. The features
90 * determine the generation of both the vertex and fragment shaders.
91 * A ProgramDescription must be used in conjunction with a ProgramCache.
92 */
93struct ProgramDescription {
94    enum ColorModifier {
95        kColorNone,
96        kColorMatrix,
97        kColorLighting,
98        kColorBlend
99    };
100
101    enum Gradient {
102        kGradientLinear,
103        kGradientCircular,
104        kGradientSweep
105    };
106
107    ProgramDescription():
108        hasTexture(false), hasAlpha8Texture(false), modulate(false),
109        hasBitmap(false), isBitmapNpot(false), hasGradient(false),
110        gradientType(kGradientLinear),
111        shadersMode(SkXfermode::kClear_Mode), isBitmapFirst(false),
112        bitmapWrapS(GL_CLAMP_TO_EDGE), bitmapWrapT(GL_CLAMP_TO_EDGE),
113        colorOp(kColorNone), colorMode(SkXfermode::kClear_Mode),
114        framebufferMode(SkXfermode::kClear_Mode), swapSrcDst(false) {
115    }
116
117    // Texturing
118    bool hasTexture;
119    bool hasAlpha8Texture;
120
121    // Modulate, this should only be set when setColor() return true
122    bool modulate;
123
124    // Shaders
125    bool hasBitmap;
126    bool isBitmapNpot;
127
128    bool hasGradient;
129    Gradient gradientType;
130
131    SkXfermode::Mode shadersMode;
132
133    bool isBitmapFirst;
134    GLenum bitmapWrapS;
135    GLenum bitmapWrapT;
136
137    // Color operations
138    int colorOp;
139    SkXfermode::Mode colorMode;
140
141    // Framebuffer blending (requires Extensions.hasFramebufferFetch())
142    // Ignored for all values < SkXfermode::kPlus_Mode
143    SkXfermode::Mode framebufferMode;
144    bool swapSrcDst;
145
146    /**
147     * Indicates, for a given color, whether color modulation is required in
148     * the fragment shader. When this method returns true, the program should
149     * be provided with a modulation color.
150     */
151    bool setColor(const float r, const float g, const float b, const float a) {
152        modulate = a < COLOR_COMPONENT_THRESHOLD || r < COLOR_COMPONENT_THRESHOLD ||
153                g < COLOR_COMPONENT_THRESHOLD || b < COLOR_COMPONENT_THRESHOLD;
154        return modulate;
155    }
156
157    /**
158     * Indicates, for a given color, whether color modulation is required in
159     * the fragment shader. When this method returns true, the program should
160     * be provided with a modulation color.
161     */
162    bool setAlpha8Color(const float r, const float g, const float b, const float a) {
163        modulate = a < COLOR_COMPONENT_THRESHOLD || r > COLOR_COMPONENT_INV_THRESHOLD ||
164                g > COLOR_COMPONENT_INV_THRESHOLD || b > COLOR_COMPONENT_INV_THRESHOLD;
165        return modulate;
166    }
167
168    /**
169     * Computes the unique key identifying this program.
170     */
171    programid key() const {
172        programid key = 0;
173        if (hasTexture) key |= PROGRAM_KEY_TEXTURE;
174        if (hasAlpha8Texture) key |= PROGRAM_KEY_A8_TEXTURE;
175        if (hasBitmap) {
176            key |= PROGRAM_KEY_BITMAP;
177            if (isBitmapNpot) {
178                key |= PROGRAM_KEY_BITMAP_NPOT;
179                key |= getEnumForWrap(bitmapWrapS) << PROGRAM_BITMAP_WRAPS_SHIFT;
180                key |= getEnumForWrap(bitmapWrapT) << PROGRAM_BITMAP_WRAPT_SHIFT;
181            }
182        }
183        if (hasGradient) key |= PROGRAM_KEY_GRADIENT;
184        key |= programid(gradientType) << PROGRAM_GRADIENT_TYPE_SHIFT;
185        if (isBitmapFirst) key |= PROGRAM_KEY_BITMAP_FIRST;
186        if (hasBitmap && hasGradient) {
187            key |= (shadersMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_SHADER_SHIFT;
188        }
189        switch (colorOp) {
190            case kColorMatrix:
191                key |= PROGRAM_KEY_COLOR_MATRIX;
192                break;
193            case kColorLighting:
194                key |= PROGRAM_KEY_COLOR_LIGHTING;
195                break;
196            case kColorBlend:
197                key |= PROGRAM_KEY_COLOR_BLEND;
198                key |= (colorMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_COLOR_OP_SHIFT;
199                break;
200            case kColorNone:
201                break;
202        }
203        key |= (framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT;
204        if (swapSrcDst) key |= PROGRAM_KEY_SWAP_SRC_DST;
205        if (modulate) key |= programid(0x1) << PROGRAM_MODULATE;
206        return key;
207    }
208
209    /**
210     * Logs the specified message followed by the key identifying this program.
211     */
212    void log(const char* message) const {
213        programid k = key();
214        PROGRAM_LOGD("%s (key = 0x%.8x%.8x)", message, uint32_t(k >> 32),
215                uint32_t(k & 0xffffffff));
216    }
217
218private:
219    inline uint32_t getEnumForWrap(GLenum wrap) const {
220        switch (wrap) {
221            case GL_CLAMP_TO_EDGE:
222                return 0;
223            case GL_REPEAT:
224                return 1;
225            case GL_MIRRORED_REPEAT:
226                return 2;
227        }
228        return 0;
229    }
230
231}; // struct ProgramDescription
232
233/**
234 * Generates and caches program. Programs are generated based on
235 * ProgramDescriptions.
236 */
237class ProgramCache {
238public:
239    ProgramCache();
240    ~ProgramCache();
241
242    Program* get(const ProgramDescription& description);
243
244    void clear();
245
246private:
247    Program* generateProgram(const ProgramDescription& description, programid key);
248    String8 generateVertexShader(const ProgramDescription& description);
249    String8 generateFragmentShader(const ProgramDescription& description);
250    void generateBlend(String8& shader, const char* name, SkXfermode::Mode mode);
251    void generateTextureWrap(String8& shader, GLenum wrapS, GLenum wrapT);
252
253    void printLongString(const String8& shader) const;
254
255    KeyedVector<programid, Program*> mCache;
256}; // class ProgramCache
257
258}; // namespace uirenderer
259}; // namespace android
260
261#endif // ANDROID_UI_PROGRAM_CACHE_H
262