ProgramCache.h revision 24edca8b526515979778e577191089a57f5277d7
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_HWUI_PROGRAM_CACHE_H
18#define ANDROID_HWUI_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 "Debug.h"
29#include "Program.h"
30#include "Properties.h"
31
32namespace android {
33namespace uirenderer {
34
35///////////////////////////////////////////////////////////////////////////////
36// Defines
37///////////////////////////////////////////////////////////////////////////////
38
39// Debug
40#if DEBUG_PROGRAMS
41    #define PROGRAM_LOGD(...) LOGD(__VA_ARGS__)
42#else
43    #define PROGRAM_LOGD(...)
44#endif
45
46#define COLOR_COMPONENT_THRESHOLD (1.0f - (0.5f / PANEL_BIT_DEPTH))
47#define COLOR_COMPONENT_INV_THRESHOLD (0.5f / PANEL_BIT_DEPTH)
48
49#define PROGRAM_KEY_TEXTURE 0x1
50#define PROGRAM_KEY_A8_TEXTURE 0x2
51#define PROGRAM_KEY_BITMAP 0x4
52#define PROGRAM_KEY_GRADIENT 0x8
53#define PROGRAM_KEY_BITMAP_FIRST 0x10
54#define PROGRAM_KEY_COLOR_MATRIX 0x20
55#define PROGRAM_KEY_COLOR_LIGHTING 0x40
56#define PROGRAM_KEY_COLOR_BLEND 0x80
57#define PROGRAM_KEY_BITMAP_NPOT 0x100
58#define PROGRAM_KEY_SWAP_SRC_DST 0x2000
59
60#define PROGRAM_KEY_BITMAP_WRAPS_MASK 0x600
61#define PROGRAM_KEY_BITMAP_WRAPT_MASK 0x1800
62
63// Encode the xfermodes on 6 bits
64#define PROGRAM_MAX_XFERMODE 0x1f
65#define PROGRAM_XFERMODE_SHADER_SHIFT 26
66#define PROGRAM_XFERMODE_COLOR_OP_SHIFT 20
67#define PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT 14
68
69#define PROGRAM_BITMAP_WRAPS_SHIFT 9
70#define PROGRAM_BITMAP_WRAPT_SHIFT 11
71
72#define PROGRAM_GRADIENT_TYPE_SHIFT 33
73#define PROGRAM_MODULATE_SHIFT 35
74
75#define PROGRAM_IS_POINT_SHIFT 36
76
77#define PROGRAM_HAS_AA_SHIFT 37
78
79#define PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT 38
80#define PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT 39
81
82///////////////////////////////////////////////////////////////////////////////
83// Types
84///////////////////////////////////////////////////////////////////////////////
85
86typedef uint64_t programid;
87
88///////////////////////////////////////////////////////////////////////////////
89// Cache
90///////////////////////////////////////////////////////////////////////////////
91
92/**
93 * Describe the features required for a given program. The features
94 * determine the generation of both the vertex and fragment shaders.
95 * A ProgramDescription must be used in conjunction with a ProgramCache.
96 */
97struct ProgramDescription {
98    enum ColorModifier {
99        kColorNone,
100        kColorMatrix,
101        kColorLighting,
102        kColorBlend
103    };
104
105    enum Gradient {
106        kGradientLinear,
107        kGradientCircular,
108        kGradientSweep
109    };
110
111    ProgramDescription() {
112        reset();
113    }
114
115    // Texturing
116    bool hasTexture;
117    bool hasAlpha8Texture;
118    bool hasExternalTexture;
119    bool hasTextureTransform;
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 isAA;
129
130    bool hasGradient;
131    Gradient gradientType;
132
133    SkXfermode::Mode shadersMode;
134
135    bool isBitmapFirst;
136    GLenum bitmapWrapS;
137    GLenum bitmapWrapT;
138
139    // Color operations
140    ColorModifier colorOp;
141    SkXfermode::Mode colorMode;
142
143    // Framebuffer blending (requires Extensions.hasFramebufferFetch())
144    // Ignored for all values < SkXfermode::kPlus_Mode
145    SkXfermode::Mode framebufferMode;
146    bool swapSrcDst;
147
148    bool isPoint;
149    float pointSize;
150
151    /**
152     * Resets this description. All fields are reset back to the default
153     * values they hold after building a new instance.
154     */
155    void reset() {
156        hasTexture = false;
157        hasAlpha8Texture = false;
158        hasExternalTexture = false;
159        hasTextureTransform = false;
160
161        isAA = false;
162
163        modulate = false;
164
165        hasBitmap = false;
166        isBitmapNpot = false;
167
168        hasGradient = false;
169        gradientType = kGradientLinear;
170
171        shadersMode = SkXfermode::kClear_Mode;
172
173        isBitmapFirst = false;
174        bitmapWrapS = GL_CLAMP_TO_EDGE;
175        bitmapWrapT = GL_CLAMP_TO_EDGE;
176
177        colorOp = kColorNone;
178        colorMode = SkXfermode::kClear_Mode;
179
180        framebufferMode = SkXfermode::kClear_Mode;
181        swapSrcDst = false;
182
183        isPoint = false;
184        pointSize = 0.0f;
185    }
186
187    /**
188     * Indicates, for a given color, whether color modulation is required in
189     * the fragment shader. When this method returns true, the program should
190     * be provided with a modulation color.
191     */
192    bool setColor(const float r, const float g, const float b, const float a) {
193        modulate = a < COLOR_COMPONENT_THRESHOLD || r < COLOR_COMPONENT_THRESHOLD ||
194                g < COLOR_COMPONENT_THRESHOLD || b < COLOR_COMPONENT_THRESHOLD;
195        return modulate;
196    }
197
198    /**
199     * Indicates, for a given color, whether color modulation is required in
200     * the fragment shader. When this method returns true, the program should
201     * be provided with a modulation color.
202     */
203    bool setAlpha8Color(const float r, const float g, const float b, const float a) {
204        modulate = a < COLOR_COMPONENT_THRESHOLD || r > COLOR_COMPONENT_INV_THRESHOLD ||
205                g > COLOR_COMPONENT_INV_THRESHOLD || b > COLOR_COMPONENT_INV_THRESHOLD;
206        return modulate;
207    }
208
209    /**
210     * Computes the unique key identifying this program.
211     */
212    programid key() const {
213        programid key = 0;
214        if (hasTexture) key |= PROGRAM_KEY_TEXTURE;
215        if (hasAlpha8Texture) key |= PROGRAM_KEY_A8_TEXTURE;
216        if (hasBitmap) {
217            key |= PROGRAM_KEY_BITMAP;
218            if (isBitmapNpot) {
219                key |= PROGRAM_KEY_BITMAP_NPOT;
220                key |= getEnumForWrap(bitmapWrapS) << PROGRAM_BITMAP_WRAPS_SHIFT;
221                key |= getEnumForWrap(bitmapWrapT) << PROGRAM_BITMAP_WRAPT_SHIFT;
222            }
223        }
224        if (hasGradient) key |= PROGRAM_KEY_GRADIENT;
225        key |= programid(gradientType) << PROGRAM_GRADIENT_TYPE_SHIFT;
226        if (isBitmapFirst) key |= PROGRAM_KEY_BITMAP_FIRST;
227        if (hasBitmap && hasGradient) {
228            key |= (shadersMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_SHADER_SHIFT;
229        }
230        switch (colorOp) {
231            case kColorMatrix:
232                key |= PROGRAM_KEY_COLOR_MATRIX;
233                break;
234            case kColorLighting:
235                key |= PROGRAM_KEY_COLOR_LIGHTING;
236                break;
237            case kColorBlend:
238                key |= PROGRAM_KEY_COLOR_BLEND;
239                key |= (colorMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_COLOR_OP_SHIFT;
240                break;
241            case kColorNone:
242                break;
243        }
244        key |= (framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT;
245        if (swapSrcDst) key |= PROGRAM_KEY_SWAP_SRC_DST;
246        if (modulate) key |= programid(0x1) << PROGRAM_MODULATE_SHIFT;
247        if (isPoint) key |= programid(0x1) << PROGRAM_IS_POINT_SHIFT;
248        if (isAA) key |= programid(0x1) << PROGRAM_HAS_AA_SHIFT;
249        if (hasExternalTexture) key |= programid(0x1) << PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT;
250        if (hasTextureTransform) key |= programid(0x1) << PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT;
251        return key;
252    }
253
254    /**
255     * Logs the specified message followed by the key identifying this program.
256     */
257    void log(const char* message) const {
258#if DEBUG_PROGRAMS
259        programid k = key();
260        PROGRAM_LOGD("%s (key = 0x%.8x%.8x)", message, uint32_t(k >> 32),
261                uint32_t(k & 0xffffffff));
262#endif
263    }
264
265private:
266    inline uint32_t getEnumForWrap(GLenum wrap) const {
267        switch (wrap) {
268            case GL_CLAMP_TO_EDGE:
269                return 0;
270            case GL_REPEAT:
271                return 1;
272            case GL_MIRRORED_REPEAT:
273                return 2;
274        }
275        return 0;
276    }
277
278}; // struct ProgramDescription
279
280/**
281 * Generates and caches program. Programs are generated based on
282 * ProgramDescriptions.
283 */
284class ProgramCache {
285public:
286    ProgramCache();
287    ~ProgramCache();
288
289    Program* get(const ProgramDescription& description);
290
291    void clear();
292
293private:
294    Program* generateProgram(const ProgramDescription& description, programid key);
295    String8 generateVertexShader(const ProgramDescription& description);
296    String8 generateFragmentShader(const ProgramDescription& description);
297    void generateBlend(String8& shader, const char* name, SkXfermode::Mode mode);
298    void generateTextureWrap(String8& shader, GLenum wrapS, GLenum wrapT);
299
300    void printLongString(const String8& shader) const;
301
302    KeyedVector<programid, Program*> mCache;
303}; // class ProgramCache
304
305}; // namespace uirenderer
306}; // namespace android
307
308#endif // ANDROID_HWUI_PROGRAM_CACHE_H
309