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