ProgramCache.h revision 6fca9884b3ea24d5775af4cf713fd81506913a39
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///////////////////////////////////////////////////////////////////////////////
81// Types
82///////////////////////////////////////////////////////////////////////////////
83
84typedef uint64_t programid;
85
86///////////////////////////////////////////////////////////////////////////////
87// Cache
88///////////////////////////////////////////////////////////////////////////////
89
90/**
91 * Describe the features required for a given program. The features
92 * determine the generation of both the vertex and fragment shaders.
93 * A ProgramDescription must be used in conjunction with a ProgramCache.
94 */
95struct ProgramDescription {
96    enum ColorModifier {
97        kColorNone,
98        kColorMatrix,
99        kColorLighting,
100        kColorBlend
101    };
102
103    enum Gradient {
104        kGradientLinear,
105        kGradientCircular,
106        kGradientSweep
107    };
108
109    ProgramDescription() {
110        reset();
111    }
112
113    // Texturing
114    bool hasTexture;
115    bool hasAlpha8Texture;
116
117    // Modulate, this should only be set when setColor() return true
118    bool modulate;
119
120    // Shaders
121    bool hasBitmap;
122    bool isBitmapNpot;
123
124    bool hasWidth;
125
126    bool hasGradient;
127    Gradient gradientType;
128
129    SkXfermode::Mode shadersMode;
130
131    bool isBitmapFirst;
132    GLenum bitmapWrapS;
133    GLenum bitmapWrapT;
134
135    // Color operations
136    ColorModifier colorOp;
137    SkXfermode::Mode colorMode;
138
139    // Framebuffer blending (requires Extensions.hasFramebufferFetch())
140    // Ignored for all values < SkXfermode::kPlus_Mode
141    SkXfermode::Mode framebufferMode;
142    bool swapSrcDst;
143
144    bool isPoint;
145    float pointSize;
146
147    /**
148     * Resets this description. All fields are reset back to the default
149     * values they hold after building a new instance.
150     */
151    void reset() {
152        hasTexture = false;
153        hasAlpha8Texture = false;
154
155        hasWidth = false;
156
157        modulate = false;
158
159        hasBitmap = false;
160        isBitmapNpot = false;
161
162        hasGradient = false;
163        gradientType = kGradientLinear;
164
165        shadersMode = SkXfermode::kClear_Mode;
166
167        isBitmapFirst = false;
168        bitmapWrapS = GL_CLAMP_TO_EDGE;
169        bitmapWrapT = GL_CLAMP_TO_EDGE;
170
171        colorOp = kColorNone;
172        colorMode = SkXfermode::kClear_Mode;
173
174        framebufferMode = SkXfermode::kClear_Mode;
175        swapSrcDst = false;
176
177        isPoint = false;
178        pointSize = 0.0f;
179    }
180
181    /**
182     * Indicates, for a given color, whether color modulation is required in
183     * the fragment shader. When this method returns true, the program should
184     * be provided with a modulation color.
185     */
186    bool setColor(const float r, const float g, const float b, const float a) {
187        modulate = a < COLOR_COMPONENT_THRESHOLD || r < COLOR_COMPONENT_THRESHOLD ||
188                g < COLOR_COMPONENT_THRESHOLD || b < COLOR_COMPONENT_THRESHOLD;
189        return modulate;
190    }
191
192    /**
193     * Indicates, for a given color, whether color modulation is required in
194     * the fragment shader. When this method returns true, the program should
195     * be provided with a modulation color.
196     */
197    bool setAlpha8Color(const float r, const float g, const float b, const float a) {
198        modulate = a < COLOR_COMPONENT_THRESHOLD || r > COLOR_COMPONENT_INV_THRESHOLD ||
199                g > COLOR_COMPONENT_INV_THRESHOLD || b > COLOR_COMPONENT_INV_THRESHOLD;
200        return modulate;
201    }
202
203    /**
204     * Computes the unique key identifying this program.
205     */
206    programid key() const {
207        programid key = 0;
208        if (hasTexture) key |= PROGRAM_KEY_TEXTURE;
209        if (hasAlpha8Texture) key |= PROGRAM_KEY_A8_TEXTURE;
210        if (hasBitmap) {
211            key |= PROGRAM_KEY_BITMAP;
212            if (isBitmapNpot) {
213                key |= PROGRAM_KEY_BITMAP_NPOT;
214                key |= getEnumForWrap(bitmapWrapS) << PROGRAM_BITMAP_WRAPS_SHIFT;
215                key |= getEnumForWrap(bitmapWrapT) << PROGRAM_BITMAP_WRAPT_SHIFT;
216            }
217        }
218        if (hasGradient) key |= PROGRAM_KEY_GRADIENT;
219        key |= programid(gradientType) << PROGRAM_GRADIENT_TYPE_SHIFT;
220        if (isBitmapFirst) key |= PROGRAM_KEY_BITMAP_FIRST;
221        if (hasBitmap && hasGradient) {
222            key |= (shadersMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_SHADER_SHIFT;
223        }
224        switch (colorOp) {
225            case kColorMatrix:
226                key |= PROGRAM_KEY_COLOR_MATRIX;
227                break;
228            case kColorLighting:
229                key |= PROGRAM_KEY_COLOR_LIGHTING;
230                break;
231            case kColorBlend:
232                key |= PROGRAM_KEY_COLOR_BLEND;
233                key |= (colorMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_COLOR_OP_SHIFT;
234                break;
235            case kColorNone:
236                break;
237        }
238        key |= (framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT;
239        if (swapSrcDst) key |= PROGRAM_KEY_SWAP_SRC_DST;
240        if (modulate) key |= programid(0x1) << PROGRAM_MODULATE_SHIFT;
241        if (isPoint) key |= programid(0x1) << PROGRAM_IS_POINT_SHIFT;
242        if (hasWidth) key |= programid(0x1) << PROGRAM_HAS_WIDTH_SHIFT;
243        return key;
244    }
245
246    /**
247     * Logs the specified message followed by the key identifying this program.
248     */
249    void log(const char* message) const {
250#if DEBUG_PROGRAMS
251        programid k = key();
252        PROGRAM_LOGD("%s (key = 0x%.8x%.8x)", message, uint32_t(k >> 32),
253                uint32_t(k & 0xffffffff));
254#endif
255    }
256
257private:
258    inline uint32_t getEnumForWrap(GLenum wrap) const {
259        switch (wrap) {
260            case GL_CLAMP_TO_EDGE:
261                return 0;
262            case GL_REPEAT:
263                return 1;
264            case GL_MIRRORED_REPEAT:
265                return 2;
266        }
267        return 0;
268    }
269
270}; // struct ProgramDescription
271
272/**
273 * Generates and caches program. Programs are generated based on
274 * ProgramDescriptions.
275 */
276class ProgramCache {
277public:
278    ProgramCache();
279    ~ProgramCache();
280
281    Program* get(const ProgramDescription& description);
282
283    void clear();
284
285private:
286    Program* generateProgram(const ProgramDescription& description, programid key);
287    String8 generateVertexShader(const ProgramDescription& description);
288    String8 generateFragmentShader(const ProgramDescription& description);
289    void generateBlend(String8& shader, const char* name, SkXfermode::Mode mode);
290    void generateTextureWrap(String8& shader, GLenum wrapS, GLenum wrapT);
291
292    void printLongString(const String8& shader) const;
293
294    KeyedVector<programid, Program*> mCache;
295}; // class ProgramCache
296
297}; // namespace uirenderer
298}; // namespace android
299
300#endif // ANDROID_HWUI_PROGRAM_CACHE_H
301