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_H
18#define ANDROID_HWUI_PROGRAM_H
19
20#include <utils/KeyedVector.h>
21
22#include <GLES2/gl2.h>
23#include <GLES2/gl2ext.h>
24
25#include <SkXfermode.h>
26
27#include "Debug.h"
28#include "Matrix.h"
29#include "Properties.h"
30
31namespace android {
32namespace uirenderer {
33
34///////////////////////////////////////////////////////////////////////////////
35// Defines
36///////////////////////////////////////////////////////////////////////////////
37
38// Debug
39#if DEBUG_PROGRAMS
40    #define PROGRAM_LOGD(...) ALOGD(__VA_ARGS__)
41#else
42    #define PROGRAM_LOGD(...)
43#endif
44
45#define COLOR_COMPONENT_THRESHOLD 1.0f
46#define COLOR_COMPONENT_INV_THRESHOLD 0.0f
47
48#define PROGRAM_KEY_TEXTURE             0x01
49#define PROGRAM_KEY_A8_TEXTURE          0x02
50#define PROGRAM_KEY_BITMAP              0x04
51#define PROGRAM_KEY_GRADIENT            0x08
52#define PROGRAM_KEY_BITMAP_FIRST        0x10
53#define PROGRAM_KEY_COLOR_MATRIX        0x20
54#define PROGRAM_KEY_COLOR_BLEND         0x40
55#define PROGRAM_KEY_BITMAP_NPOT         0x80
56
57#define PROGRAM_KEY_SWAP_SRC_DST      0x2000
58
59#define PROGRAM_KEY_BITMAP_WRAPS_MASK  0x600
60#define PROGRAM_KEY_BITMAP_WRAPT_MASK 0x1800
61
62// Encode the xfermodes on 6 bits
63#define PROGRAM_MAX_XFERMODE 0x1f
64#define PROGRAM_XFERMODE_SHADER_SHIFT 26
65#define PROGRAM_XFERMODE_COLOR_OP_SHIFT 20
66#define PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT 14
67
68#define PROGRAM_BITMAP_WRAPS_SHIFT 9
69#define PROGRAM_BITMAP_WRAPT_SHIFT 11
70
71#define PROGRAM_GRADIENT_TYPE_SHIFT 33 // 2 bits for gradient type
72#define PROGRAM_MODULATE_SHIFT 35
73
74#define PROGRAM_HAS_VERTEX_ALPHA_SHIFT 36
75#define PROGRAM_USE_SHADOW_ALPHA_INTERP_SHIFT 37
76
77#define PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT 38
78#define PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT 39
79
80#define PROGRAM_HAS_GAMMA_CORRECTION 40
81
82#define PROGRAM_IS_SIMPLE_GRADIENT 41
83
84#define PROGRAM_HAS_COLORS 42
85
86#define PROGRAM_HAS_DEBUG_HIGHLIGHT 43
87#define PROGRAM_HAS_ROUND_RECT_CLIP 44
88
89///////////////////////////////////////////////////////////////////////////////
90// Types
91///////////////////////////////////////////////////////////////////////////////
92
93typedef uint64_t programid;
94
95///////////////////////////////////////////////////////////////////////////////
96// Program description
97///////////////////////////////////////////////////////////////////////////////
98
99/**
100 * Describe the features required for a given program. The features
101 * determine the generation of both the vertex and fragment shaders.
102 * A ProgramDescription must be used in conjunction with a ProgramCache.
103 */
104struct ProgramDescription {
105    enum ColorModifier {
106        kColorNone = 0,
107        kColorMatrix,
108        kColorBlend
109    };
110
111    enum Gradient {
112        kGradientLinear = 0,
113        kGradientCircular,
114        kGradientSweep
115    };
116
117    ProgramDescription() {
118        reset();
119    }
120
121    // Texturing
122    bool hasTexture;
123    bool hasAlpha8Texture;
124    bool hasExternalTexture;
125    bool hasTextureTransform;
126
127    // Color attribute
128    bool hasColors;
129
130    // Modulate, this should only be set when setColor() return true
131    bool modulate;
132
133    // Shaders
134    bool hasBitmap;
135    bool isBitmapNpot;
136
137    bool hasVertexAlpha;
138    bool useShadowAlphaInterp;
139
140    bool hasGradient;
141    Gradient gradientType;
142    bool isSimpleGradient;
143
144    SkXfermode::Mode shadersMode;
145
146    bool isBitmapFirst;
147    GLenum bitmapWrapS;
148    GLenum bitmapWrapT;
149
150    // Color operations
151    ColorModifier colorOp;
152    SkXfermode::Mode colorMode;
153
154    // Framebuffer blending (requires Extensions.hasFramebufferFetch())
155    // Ignored for all values < SkXfermode::kPlus_Mode
156    SkXfermode::Mode framebufferMode;
157    bool swapSrcDst;
158
159    bool hasGammaCorrection;
160    float gamma;
161
162    bool hasDebugHighlight;
163    bool hasRoundRectClip;
164
165    /**
166     * Resets this description. All fields are reset back to the default
167     * values they hold after building a new instance.
168     */
169    void reset() {
170        hasTexture = false;
171        hasAlpha8Texture = false;
172        hasExternalTexture = false;
173        hasTextureTransform = false;
174
175        hasColors = false;
176
177        hasVertexAlpha = false;
178        useShadowAlphaInterp = false;
179
180        modulate = false;
181
182        hasBitmap = false;
183        isBitmapNpot = false;
184
185        hasGradient = false;
186        gradientType = kGradientLinear;
187        isSimpleGradient = false;
188
189        shadersMode = SkXfermode::kClear_Mode;
190
191        isBitmapFirst = false;
192        bitmapWrapS = GL_CLAMP_TO_EDGE;
193        bitmapWrapT = GL_CLAMP_TO_EDGE;
194
195        colorOp = kColorNone;
196        colorMode = SkXfermode::kClear_Mode;
197
198        framebufferMode = SkXfermode::kClear_Mode;
199        swapSrcDst = false;
200
201        hasGammaCorrection = false;
202        gamma = 2.2f;
203
204        hasDebugHighlight = false;
205        hasRoundRectClip = false;
206    }
207
208    /**
209     * Indicates, for a given color, whether color modulation is required in
210     * the fragment shader. When this method returns true, the program should
211     * be provided with a modulation color.
212     */
213    bool setColorModulate(const float a) {
214        modulate = a < COLOR_COMPONENT_THRESHOLD;
215        return modulate;
216    }
217
218    /**
219     * Indicates, for a given color, whether color modulation is required in
220     * the fragment shader. When this method returns true, the program should
221     * be provided with a modulation color.
222     */
223    bool setAlpha8ColorModulate(const float r, const float g, const float b, const float a) {
224        modulate = a < COLOR_COMPONENT_THRESHOLD || r > COLOR_COMPONENT_INV_THRESHOLD ||
225                g > COLOR_COMPONENT_INV_THRESHOLD || b > COLOR_COMPONENT_INV_THRESHOLD;
226        return modulate;
227    }
228
229    /**
230     * Computes the unique key identifying this program.
231     */
232    programid key() const {
233        programid key = 0;
234        if (hasTexture) key |= PROGRAM_KEY_TEXTURE;
235        if (hasAlpha8Texture) key |= PROGRAM_KEY_A8_TEXTURE;
236        if (hasBitmap) {
237            key |= PROGRAM_KEY_BITMAP;
238            if (isBitmapNpot) {
239                key |= PROGRAM_KEY_BITMAP_NPOT;
240                key |= getEnumForWrap(bitmapWrapS) << PROGRAM_BITMAP_WRAPS_SHIFT;
241                key |= getEnumForWrap(bitmapWrapT) << PROGRAM_BITMAP_WRAPT_SHIFT;
242            }
243        }
244        if (hasGradient) key |= PROGRAM_KEY_GRADIENT;
245        key |= programid(gradientType) << PROGRAM_GRADIENT_TYPE_SHIFT;
246        if (isBitmapFirst) key |= PROGRAM_KEY_BITMAP_FIRST;
247        if (hasBitmap && hasGradient) {
248            key |= (shadersMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_SHADER_SHIFT;
249        }
250        switch (colorOp) {
251            case kColorMatrix:
252                key |= PROGRAM_KEY_COLOR_MATRIX;
253                break;
254            case kColorBlend:
255                key |= PROGRAM_KEY_COLOR_BLEND;
256                key |= (colorMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_COLOR_OP_SHIFT;
257                break;
258            case kColorNone:
259                break;
260        }
261        key |= (framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT;
262        if (swapSrcDst) key |= PROGRAM_KEY_SWAP_SRC_DST;
263        if (modulate) key |= programid(0x1) << PROGRAM_MODULATE_SHIFT;
264        if (hasVertexAlpha) key |= programid(0x1) << PROGRAM_HAS_VERTEX_ALPHA_SHIFT;
265        if (useShadowAlphaInterp) key |= programid(0x1) << PROGRAM_USE_SHADOW_ALPHA_INTERP_SHIFT;
266        if (hasExternalTexture) key |= programid(0x1) << PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT;
267        if (hasTextureTransform) key |= programid(0x1) << PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT;
268        if (hasGammaCorrection) key |= programid(0x1) << PROGRAM_HAS_GAMMA_CORRECTION;
269        if (isSimpleGradient) key |= programid(0x1) << PROGRAM_IS_SIMPLE_GRADIENT;
270        if (hasColors) key |= programid(0x1) << PROGRAM_HAS_COLORS;
271        if (hasDebugHighlight) key |= programid(0x1) << PROGRAM_HAS_DEBUG_HIGHLIGHT;
272        if (hasRoundRectClip) key |= programid(0x1) << PROGRAM_HAS_ROUND_RECT_CLIP;
273        return key;
274    }
275
276    /**
277     * Logs the specified message followed by the key identifying this program.
278     */
279    void log(const char* message) const {
280#if DEBUG_PROGRAMS
281        programid k = key();
282        PROGRAM_LOGD("%s (key = 0x%.8x%.8x)", message, uint32_t(k >> 32),
283                uint32_t(k & 0xffffffff));
284#endif
285    }
286
287private:
288    static inline uint32_t getEnumForWrap(GLenum wrap) {
289        switch (wrap) {
290            case GL_CLAMP_TO_EDGE:
291                return 0;
292            case GL_REPEAT:
293                return 1;
294            case GL_MIRRORED_REPEAT:
295                return 2;
296        }
297        return 0;
298    }
299
300}; // struct ProgramDescription
301
302/**
303 * A program holds a vertex and a fragment shader. It offers several utility
304 * methods to query attributes and uniforms.
305 */
306class Program {
307public:
308    enum ShaderBindings {
309        kBindingPosition,
310        kBindingTexCoords
311    };
312
313    /**
314     * Creates a new program with the specified vertex and fragment
315     * shaders sources.
316     */
317    Program(const ProgramDescription& description, const char* vertex, const char* fragment);
318    virtual ~Program();
319
320    /**
321     * Binds this program to the GL context.
322     */
323    virtual void use();
324
325    /**
326     * Marks this program as unused. This will not unbind
327     * the program from the GL context.
328     */
329    virtual void remove();
330
331    /**
332     * Returns the OpenGL name of the specified attribute.
333     */
334    int getAttrib(const char* name);
335
336    /**
337     * Returns the OpenGL name of the specified uniform.
338     */
339    int getUniform(const char* name);
340
341    /**
342     * Indicates whether this program is currently in use with
343     * the GL context.
344     */
345    inline bool isInUse() const {
346        return mUse;
347    }
348
349    /**
350     * Indicates whether this program was correctly compiled and linked.
351     */
352    inline bool isInitialized() const {
353        return mInitialized;
354    }
355
356    /**
357     * Binds the program with the specified projection, modelView and
358     * transform matrices.
359     */
360    void set(const mat4& projectionMatrix, const mat4& modelViewMatrix,
361             const mat4& transformMatrix, bool offset = false);
362
363    /**
364     * Sets the color associated with this shader.
365     */
366    void setColor(const float r, const float g, const float b, const float a);
367
368    /**
369     * Name of the position attribute.
370     */
371    int position;
372
373    /**
374     * Name of the texCoords attribute if it exists, -1 otherwise.
375     */
376    int texCoords;
377
378    /**
379     * Name of the transform uniform.
380     */
381    int transform;
382
383    /**
384     * Name of the projection uniform.
385     */
386    int projection;
387
388protected:
389    /**
390     * Adds an attribute with the specified name.
391     *
392     * @return The OpenGL name of the attribute.
393     */
394    int addAttrib(const char* name);
395
396    /**
397     * Binds the specified attribute name to the specified slot.
398     */
399    int bindAttrib(const char* name, ShaderBindings bindingSlot);
400
401    /**
402     * Adds a uniform with the specified name.
403     *
404     * @return The OpenGL name of the uniform.
405     */
406    int addUniform(const char* name);
407
408private:
409    /**
410     * Compiles the specified shader of the specified type.
411     *
412     * @return The name of the compiled shader.
413     */
414    GLuint buildShader(const char* source, GLenum type);
415
416    // Name of the OpenGL program and shaders
417    GLuint mProgramId;
418    GLuint mVertexShader;
419    GLuint mFragmentShader;
420
421    // Keeps track of attributes and uniforms slots
422    KeyedVector<const char*, int> mAttributes;
423    KeyedVector<const char*, int> mUniforms;
424
425    bool mUse;
426    bool mInitialized;
427
428    // Uniforms caching
429    bool mHasColorUniform;
430    int mColorUniform;
431
432    bool mHasSampler;
433
434    mat4 mProjection;
435    bool mOffset;
436}; // class Program
437
438}; // namespace uirenderer
439}; // namespace android
440
441#endif // ANDROID_HWUI_PROGRAM_H
442