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