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