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