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 
31 namespace android {
32 namespace 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 
93 typedef 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  */
104 struct 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 
ProgramDescriptionProgramDescription117     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      */
resetProgramDescription169     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      */
setColorModulateProgramDescription213     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      */
setAlpha8ColorModulateProgramDescription223     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      */
keyProgramDescription232     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      */
logProgramDescription279     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 
287 private:
getEnumForWrapProgramDescription288     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  */
306 class Program {
307 public:
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      */
isInUse()345     inline bool isInUse() const {
346         return mUse;
347     }
348 
349     /**
350      * Indicates whether this program was correctly compiled and linked.
351      */
isInitialized()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 
388 protected:
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 
408 private:
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