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