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