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 #define LOG_TAG "OpenGLRenderer"
18 
19 #include <utils/String8.h>
20 
21 #include "Caches.h"
22 #include "Dither.h"
23 #include "ProgramCache.h"
24 
25 namespace android {
26 namespace uirenderer {
27 
28 ///////////////////////////////////////////////////////////////////////////////
29 // Defines
30 ///////////////////////////////////////////////////////////////////////////////
31 
32 #define MODULATE_OP_NO_MODULATE 0
33 #define MODULATE_OP_MODULATE 1
34 #define MODULATE_OP_MODULATE_A8 2
35 
36 #define STR(x) STR1(x)
37 #define STR1(x) #x
38 
39 ///////////////////////////////////////////////////////////////////////////////
40 // Vertex shaders snippets
41 ///////////////////////////////////////////////////////////////////////////////
42 
43 const char* gVS_Header_Attributes =
44         "attribute vec4 position;\n";
45 const char* gVS_Header_Attributes_TexCoords =
46         "attribute vec2 texCoords;\n";
47 const char* gVS_Header_Attributes_Colors =
48         "attribute vec4 colors;\n";
49 const char* gVS_Header_Attributes_VertexAlphaParameters =
50         "attribute float vtxAlpha;\n";
51 const char* gVS_Header_Uniforms_TextureTransform =
52         "uniform mat4 mainTextureTransform;\n";
53 const char* gVS_Header_Uniforms =
54         "uniform mat4 projection;\n" \
55         "uniform mat4 transform;\n";
56 const char* gVS_Header_Uniforms_HasGradient =
57         "uniform mat4 screenSpace;\n";
58 const char* gVS_Header_Uniforms_HasBitmap =
59         "uniform mat4 textureTransform;\n"
60         "uniform mediump vec2 textureDimension;\n";
61 const char* gVS_Header_Uniforms_HasRoundRectClip =
62         "uniform mat4 roundRectInvTransform;\n";
63 const char* gVS_Header_Varyings_HasTexture =
64         "varying vec2 outTexCoords;\n";
65 const char* gVS_Header_Varyings_HasColors =
66         "varying vec4 outColors;\n";
67 const char* gVS_Header_Varyings_HasVertexAlpha =
68         "varying float alpha;\n";
69 const char* gVS_Header_Varyings_HasBitmap =
70         "varying highp vec2 outBitmapTexCoords;\n";
71 const char* gVS_Header_Varyings_HasGradient[6] = {
72         // Linear
73         "varying highp vec2 linear;\n"
74         "varying vec2 ditherTexCoords;\n",
75         "varying float linear;\n"
76         "varying vec2 ditherTexCoords;\n",
77 
78         // Circular
79         "varying highp vec2 circular;\n"
80         "varying vec2 ditherTexCoords;\n",
81         "varying highp vec2 circular;\n"
82         "varying vec2 ditherTexCoords;\n",
83 
84         // Sweep
85         "varying highp vec2 sweep;\n"
86         "varying vec2 ditherTexCoords;\n",
87         "varying highp vec2 sweep;\n"
88         "varying vec2 ditherTexCoords;\n",
89 };
90 const char* gVS_Header_Varyings_HasRoundRectClip =
91         "varying highp vec2 roundRectPos;\n";
92 const char* gVS_Main =
93         "\nvoid main(void) {\n";
94 const char* gVS_Main_OutTexCoords =
95         "    outTexCoords = texCoords;\n";
96 const char* gVS_Main_OutColors =
97         "    outColors = colors;\n";
98 const char* gVS_Main_OutTransformedTexCoords =
99         "    outTexCoords = (mainTextureTransform * vec4(texCoords, 0.0, 1.0)).xy;\n";
100 const char* gVS_Main_OutGradient[6] = {
101         // Linear
102         "    linear = vec2((screenSpace * position).x, 0.5);\n"
103         "    ditherTexCoords = (transform * position).xy * " STR(DITHER_KERNEL_SIZE_INV) ";\n",
104         "    linear = (screenSpace * position).x;\n"
105         "    ditherTexCoords = (transform * position).xy * " STR(DITHER_KERNEL_SIZE_INV) ";\n",
106 
107         // Circular
108         "    circular = (screenSpace * position).xy;\n"
109         "    ditherTexCoords = (transform * position).xy * " STR(DITHER_KERNEL_SIZE_INV) ";\n",
110         "    circular = (screenSpace * position).xy;\n"
111         "    ditherTexCoords = (transform * position).xy * " STR(DITHER_KERNEL_SIZE_INV) ";\n",
112 
113         // Sweep
114         "    sweep = (screenSpace * position).xy;\n"
115         "    ditherTexCoords = (transform * position).xy * " STR(DITHER_KERNEL_SIZE_INV) ";\n",
116         "    sweep = (screenSpace * position).xy;\n"
117         "    ditherTexCoords = (transform * position).xy * " STR(DITHER_KERNEL_SIZE_INV) ";\n",
118 };
119 const char* gVS_Main_OutBitmapTexCoords =
120         "    outBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n";
121 const char* gVS_Main_Position =
122         "    vec4 transformedPosition = projection * transform * position;\n"
123         "    gl_Position = transformedPosition;\n";
124 
125 const char* gVS_Main_VertexAlpha =
126         "    alpha = vtxAlpha;\n";
127 
128 const char* gVS_Main_HasRoundRectClip =
129         "    roundRectPos = (roundRectInvTransform * transformedPosition).xy;\n";
130 const char* gVS_Footer =
131         "}\n\n";
132 
133 ///////////////////////////////////////////////////////////////////////////////
134 // Fragment shaders snippets
135 ///////////////////////////////////////////////////////////////////////////////
136 
137 const char* gFS_Header_Extension_FramebufferFetch =
138         "#extension GL_NV_shader_framebuffer_fetch : enable\n\n";
139 const char* gFS_Header_Extension_ExternalTexture =
140         "#extension GL_OES_EGL_image_external : require\n\n";
141 const char* gFS_Header =
142         "precision mediump float;\n\n";
143 const char* gFS_Uniforms_Color =
144         "uniform vec4 color;\n";
145 const char* gFS_Uniforms_TextureSampler =
146         "uniform sampler2D baseSampler;\n";
147 const char* gFS_Uniforms_ExternalTextureSampler =
148         "uniform samplerExternalOES baseSampler;\n";
149 const char* gFS_Uniforms_Dither =
150         "uniform sampler2D ditherSampler;";
151 const char* gFS_Uniforms_GradientSampler[2] = {
152         "%s\n"
153         "uniform sampler2D gradientSampler;\n",
154         "%s\n"
155         "uniform vec4 startColor;\n"
156         "uniform vec4 endColor;\n"
157 };
158 const char* gFS_Uniforms_BitmapSampler =
159         "uniform sampler2D bitmapSampler;\n";
160 const char* gFS_Uniforms_ColorOp[3] = {
161         // None
162         "",
163         // Matrix
164         "uniform mat4 colorMatrix;\n"
165         "uniform vec4 colorMatrixVector;\n",
166         // PorterDuff
167         "uniform vec4 colorBlend;\n"
168 };
169 const char* gFS_Uniforms_Gamma =
170         "uniform float gamma;\n";
171 
172 const char* gFS_Uniforms_HasRoundRectClip =
173         "uniform vec4 roundRectInnerRectLTRB;\n"
174         "uniform float roundRectRadius;\n";
175 
176 const char* gFS_Main =
177         "\nvoid main(void) {\n"
178         "    lowp vec4 fragColor;\n";
179 
180 const char* gFS_Main_Dither[2] = {
181         // ES 2.0
182         "texture2D(ditherSampler, ditherTexCoords).a * " STR(DITHER_KERNEL_SIZE_INV_SQUARE),
183         // ES 3.0
184         "texture2D(ditherSampler, ditherTexCoords).a"
185 };
186 const char* gFS_Main_AddDitherToGradient =
187         "    gradientColor += %s;\n";
188 
189 // Fast cases
190 const char* gFS_Fast_SingleColor =
191         "\nvoid main(void) {\n"
192         "    gl_FragColor = color;\n"
193         "}\n\n";
194 const char* gFS_Fast_SingleTexture =
195         "\nvoid main(void) {\n"
196         "    gl_FragColor = texture2D(baseSampler, outTexCoords);\n"
197         "}\n\n";
198 const char* gFS_Fast_SingleModulateTexture =
199         "\nvoid main(void) {\n"
200         "    gl_FragColor = color.a * texture2D(baseSampler, outTexCoords);\n"
201         "}\n\n";
202 const char* gFS_Fast_SingleA8Texture =
203         "\nvoid main(void) {\n"
204         "    gl_FragColor = texture2D(baseSampler, outTexCoords);\n"
205         "}\n\n";
206 const char* gFS_Fast_SingleA8Texture_ApplyGamma =
207         "\nvoid main(void) {\n"
208         "    gl_FragColor = vec4(0.0, 0.0, 0.0, pow(texture2D(baseSampler, outTexCoords).a, gamma));\n"
209         "}\n\n";
210 const char* gFS_Fast_SingleModulateA8Texture =
211         "\nvoid main(void) {\n"
212         "    gl_FragColor = color * texture2D(baseSampler, outTexCoords).a;\n"
213         "}\n\n";
214 const char* gFS_Fast_SingleModulateA8Texture_ApplyGamma =
215         "\nvoid main(void) {\n"
216         "    gl_FragColor = color * pow(texture2D(baseSampler, outTexCoords).a, gamma);\n"
217         "}\n\n";
218 const char* gFS_Fast_SingleGradient[2] = {
219         "\nvoid main(void) {\n"
220         "    gl_FragColor = %s + texture2D(gradientSampler, linear);\n"
221         "}\n\n",
222         "\nvoid main(void) {\n"
223         "    gl_FragColor = %s + mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n"
224         "}\n\n",
225 };
226 const char* gFS_Fast_SingleModulateGradient[2] = {
227         "\nvoid main(void) {\n"
228         "    gl_FragColor = %s + color.a * texture2D(gradientSampler, linear);\n"
229         "}\n\n",
230         "\nvoid main(void) {\n"
231         "    gl_FragColor = %s + color.a * mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n"
232         "}\n\n"
233 };
234 
235 // General case
236 const char* gFS_Main_FetchColor =
237         "    fragColor = color;\n";
238 const char* gFS_Main_ModulateColor =
239         "    fragColor *= color.a;\n";
240 const char* gFS_Main_ApplyVertexAlphaLinearInterp =
241         "    fragColor *= alpha;\n";
242 const char* gFS_Main_ApplyVertexAlphaShadowInterp =
243         // Use a gaussian function for the shadow fall off. Note that alpha here
244         // is actually (1.0 - alpha) for saving computation.
245         "    fragColor *= exp(- alpha * alpha * 4.0) - 0.018;\n";
246 const char* gFS_Main_FetchTexture[2] = {
247         // Don't modulate
248         "    fragColor = texture2D(baseSampler, outTexCoords);\n",
249         // Modulate
250         "    fragColor = color * texture2D(baseSampler, outTexCoords);\n"
251 };
252 const char* gFS_Main_FetchA8Texture[4] = {
253         // Don't modulate
254         "    fragColor = texture2D(baseSampler, outTexCoords);\n",
255         "    fragColor = texture2D(baseSampler, outTexCoords);\n",
256         // Modulate
257         "    fragColor = color * texture2D(baseSampler, outTexCoords).a;\n",
258         "    fragColor = color * pow(texture2D(baseSampler, outTexCoords).a, gamma);\n"
259 };
260 const char* gFS_Main_FetchGradient[6] = {
261         // Linear
262         "    vec4 gradientColor = texture2D(gradientSampler, linear);\n",
263 
264         "    vec4 gradientColor = mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n",
265 
266         // Circular
267         "    vec4 gradientColor = texture2D(gradientSampler, vec2(length(circular), 0.5));\n",
268 
269         "    vec4 gradientColor = mix(startColor, endColor, clamp(length(circular), 0.0, 1.0));\n",
270 
271         // Sweep
272         "    highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
273         "    vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n",
274 
275         "    highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
276         "    vec4 gradientColor = mix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n"
277 };
278 const char* gFS_Main_FetchBitmap =
279         "    vec4 bitmapColor = texture2D(bitmapSampler, outBitmapTexCoords);\n";
280 const char* gFS_Main_FetchBitmapNpot =
281         "    vec4 bitmapColor = texture2D(bitmapSampler, wrap(outBitmapTexCoords));\n";
282 const char* gFS_Main_BlendShadersBG =
283         "    fragColor = blendShaders(gradientColor, bitmapColor)";
284 const char* gFS_Main_BlendShadersGB =
285         "    fragColor = blendShaders(bitmapColor, gradientColor)";
286 const char* gFS_Main_BlendShaders_Modulate[6] = {
287         // Don't modulate
288         ";\n",
289         ";\n",
290         // Modulate
291         " * color.a;\n",
292         " * color.a;\n",
293         // Modulate with alpha 8 texture
294         " * texture2D(baseSampler, outTexCoords).a;\n",
295         " * pow(texture2D(baseSampler, outTexCoords).a, gamma);\n"
296 };
297 const char* gFS_Main_GradientShader_Modulate[6] = {
298         // Don't modulate
299         "    fragColor = gradientColor;\n",
300         "    fragColor = gradientColor;\n",
301         // Modulate
302         "    fragColor = gradientColor * color.a;\n",
303         "    fragColor = gradientColor * color.a;\n",
304         // Modulate with alpha 8 texture
305         "    fragColor = gradientColor * texture2D(baseSampler, outTexCoords).a;\n",
306         "    fragColor = gradientColor * pow(texture2D(baseSampler, outTexCoords).a, gamma);\n"
307     };
308 const char* gFS_Main_BitmapShader_Modulate[6] = {
309         // Don't modulate
310         "    fragColor = bitmapColor;\n",
311         "    fragColor = bitmapColor;\n",
312         // Modulate
313         "    fragColor = bitmapColor * color.a;\n",
314         "    fragColor = bitmapColor * color.a;\n",
315         // Modulate with alpha 8 texture
316         "    fragColor = bitmapColor * texture2D(baseSampler, outTexCoords).a;\n",
317         "    fragColor = bitmapColor * pow(texture2D(baseSampler, outTexCoords).a, gamma);\n"
318     };
319 const char* gFS_Main_FragColor =
320         "    gl_FragColor = fragColor;\n";
321 const char* gFS_Main_FragColor_HasColors =
322         "    gl_FragColor *= outColors;\n";
323 const char* gFS_Main_FragColor_Blend =
324         "    gl_FragColor = blendFramebuffer(fragColor, gl_LastFragColor);\n";
325 const char* gFS_Main_FragColor_Blend_Swap =
326         "    gl_FragColor = blendFramebuffer(gl_LastFragColor, fragColor);\n";
327 const char* gFS_Main_ApplyColorOp[3] = {
328         // None
329         "",
330         // Matrix
331         "    fragColor.rgb /= (fragColor.a + 0.0019);\n" // un-premultiply
332         "    fragColor *= colorMatrix;\n"
333         "    fragColor += colorMatrixVector;\n"
334         "    fragColor.rgb *= (fragColor.a + 0.0019);\n", // re-premultiply
335         // PorterDuff
336         "    fragColor = blendColors(colorBlend, fragColor);\n"
337 };
338 
339 // Note: LTRB -> xyzw
340 const char* gFS_Main_FragColor_HasRoundRectClip =
341         "    mediump vec2 fragToLT = roundRectInnerRectLTRB.xy - roundRectPos;\n"
342         "    mediump vec2 fragFromRB = roundRectPos - roundRectInnerRectLTRB.zw;\n"
343 
344         // divide + multiply by 128 to avoid falling out of range in length() function
345         "    mediump vec2 dist = max(max(fragToLT, fragFromRB), vec2(0.0, 0.0)) / 128.0;\n"
346         "    mediump float linearDist = roundRectRadius - (length(dist) * 128.0);\n"
347         "    gl_FragColor *= clamp(linearDist, 0.0, 1.0);\n";
348 
349 const char* gFS_Main_DebugHighlight =
350         "    gl_FragColor.rgb = vec3(0.0, gl_FragColor.a, 0.0);\n";
351 const char* gFS_Footer =
352         "}\n\n";
353 
354 ///////////////////////////////////////////////////////////////////////////////
355 // PorterDuff snippets
356 ///////////////////////////////////////////////////////////////////////////////
357 
358 const char* gBlendOps[18] = {
359         // Clear
360         "return vec4(0.0, 0.0, 0.0, 0.0);\n",
361         // Src
362         "return src;\n",
363         // Dst
364         "return dst;\n",
365         // SrcOver
366         "return src + dst * (1.0 - src.a);\n",
367         // DstOver
368         "return dst + src * (1.0 - dst.a);\n",
369         // SrcIn
370         "return src * dst.a;\n",
371         // DstIn
372         "return dst * src.a;\n",
373         // SrcOut
374         "return src * (1.0 - dst.a);\n",
375         // DstOut
376         "return dst * (1.0 - src.a);\n",
377         // SrcAtop
378         "return vec4(src.rgb * dst.a + (1.0 - src.a) * dst.rgb, dst.a);\n",
379         // DstAtop
380         "return vec4(dst.rgb * src.a + (1.0 - dst.a) * src.rgb, src.a);\n",
381         // Xor
382         "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb, "
383                 "src.a + dst.a - 2.0 * src.a * dst.a);\n",
384         // Plus
385         "return min(src + dst, 1.0);\n",
386         // Modulate
387         "return src * dst;\n",
388         // Screen
389         "return src + dst - src * dst;\n",
390         // Overlay
391         "return clamp(vec4(mix("
392                 "2.0 * src.rgb * dst.rgb + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), "
393                 "src.a * dst.a - 2.0 * (dst.a - dst.rgb) * (src.a - src.rgb) + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), "
394                 "step(dst.a, 2.0 * dst.rgb)), "
395                 "src.a + dst.a - src.a * dst.a), 0.0, 1.0);\n",
396         // Darken
397         "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + "
398                 "min(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n",
399         // Lighten
400         "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + "
401                 "max(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n",
402 };
403 
404 ///////////////////////////////////////////////////////////////////////////////
405 // Constructors/destructors
406 ///////////////////////////////////////////////////////////////////////////////
407 
ProgramCache(Extensions & extensions)408 ProgramCache::ProgramCache(Extensions& extensions)
409         : mHasES3(extensions.getMajorGlVersion() >= 3) {
410 }
411 
~ProgramCache()412 ProgramCache::~ProgramCache() {
413     clear();
414 }
415 
416 ///////////////////////////////////////////////////////////////////////////////
417 // Cache management
418 ///////////////////////////////////////////////////////////////////////////////
419 
clear()420 void ProgramCache::clear() {
421     PROGRAM_LOGD("Clearing program cache");
422     mCache.clear();
423 }
424 
get(const ProgramDescription & description)425 Program* ProgramCache::get(const ProgramDescription& description) {
426     programid key = description.key();
427     if (key == (PROGRAM_KEY_TEXTURE | PROGRAM_KEY_A8_TEXTURE)) {
428         // program for A8, unmodulated, texture w/o shader (black text/path textures) is equivalent
429         // to standard texture program (bitmaps, patches). Consider them equivalent.
430         key = PROGRAM_KEY_TEXTURE;
431     }
432 
433     auto iter = mCache.find(key);
434     Program* program = nullptr;
435     if (iter == mCache.end()) {
436         description.log("Could not find program");
437         program = generateProgram(description, key);
438         mCache[key] = std::unique_ptr<Program>(program);
439     } else {
440         program = iter->second.get();
441     }
442     return program;
443 }
444 
445 ///////////////////////////////////////////////////////////////////////////////
446 // Program generation
447 ///////////////////////////////////////////////////////////////////////////////
448 
generateProgram(const ProgramDescription & description,programid key)449 Program* ProgramCache::generateProgram(const ProgramDescription& description, programid key) {
450     String8 vertexShader = generateVertexShader(description);
451     String8 fragmentShader = generateFragmentShader(description);
452 
453     return new Program(description, vertexShader.string(), fragmentShader.string());
454 }
455 
gradientIndex(const ProgramDescription & description)456 static inline size_t gradientIndex(const ProgramDescription& description) {
457     return description.gradientType * 2 + description.isSimpleGradient;
458 }
459 
generateVertexShader(const ProgramDescription & description)460 String8 ProgramCache::generateVertexShader(const ProgramDescription& description) {
461     // Add attributes
462     String8 shader(gVS_Header_Attributes);
463     if (description.hasTexture || description.hasExternalTexture) {
464         shader.append(gVS_Header_Attributes_TexCoords);
465     }
466     if (description.hasVertexAlpha) {
467         shader.append(gVS_Header_Attributes_VertexAlphaParameters);
468     }
469     if (description.hasColors) {
470         shader.append(gVS_Header_Attributes_Colors);
471     }
472     // Uniforms
473     shader.append(gVS_Header_Uniforms);
474     if (description.hasTextureTransform) {
475         shader.append(gVS_Header_Uniforms_TextureTransform);
476     }
477     if (description.hasGradient) {
478         shader.append(gVS_Header_Uniforms_HasGradient);
479     }
480     if (description.hasBitmap) {
481         shader.append(gVS_Header_Uniforms_HasBitmap);
482     }
483     if (description.hasRoundRectClip) {
484         shader.append(gVS_Header_Uniforms_HasRoundRectClip);
485     }
486     // Varyings
487     if (description.hasTexture || description.hasExternalTexture) {
488         shader.append(gVS_Header_Varyings_HasTexture);
489     }
490     if (description.hasVertexAlpha) {
491         shader.append(gVS_Header_Varyings_HasVertexAlpha);
492     }
493     if (description.hasColors) {
494         shader.append(gVS_Header_Varyings_HasColors);
495     }
496     if (description.hasGradient) {
497         shader.append(gVS_Header_Varyings_HasGradient[gradientIndex(description)]);
498     }
499     if (description.hasBitmap) {
500         shader.append(gVS_Header_Varyings_HasBitmap);
501     }
502     if (description.hasRoundRectClip) {
503         shader.append(gVS_Header_Varyings_HasRoundRectClip);
504     }
505 
506     // Begin the shader
507     shader.append(gVS_Main); {
508         if (description.hasTextureTransform) {
509             shader.append(gVS_Main_OutTransformedTexCoords);
510         } else if (description.hasTexture || description.hasExternalTexture) {
511             shader.append(gVS_Main_OutTexCoords);
512         }
513         if (description.hasVertexAlpha) {
514             shader.append(gVS_Main_VertexAlpha);
515         }
516         if (description.hasColors) {
517             shader.append(gVS_Main_OutColors);
518         }
519         if (description.hasBitmap) {
520             shader.append(gVS_Main_OutBitmapTexCoords);
521         }
522         // Output transformed position
523         shader.append(gVS_Main_Position);
524         if (description.hasGradient) {
525             shader.append(gVS_Main_OutGradient[gradientIndex(description)]);
526         }
527         if (description.hasRoundRectClip) {
528             shader.append(gVS_Main_HasRoundRectClip);
529         }
530     }
531     // End the shader
532     shader.append(gVS_Footer);
533 
534     PROGRAM_LOGD("*** Generated vertex shader:\n\n%s", shader.string());
535 
536     return shader;
537 }
538 
shaderOp(const ProgramDescription & description,String8 & shader,const int modulateOp,const char ** snippets)539 static bool shaderOp(const ProgramDescription& description, String8& shader,
540         const int modulateOp, const char** snippets) {
541     int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp;
542     op = op * 2 + description.hasGammaCorrection;
543     shader.append(snippets[op]);
544     return description.hasAlpha8Texture;
545 }
546 
generateFragmentShader(const ProgramDescription & description)547 String8 ProgramCache::generateFragmentShader(const ProgramDescription& description) {
548     String8 shader;
549 
550     const bool blendFramebuffer = description.framebufferMode >= SkXfermode::kPlus_Mode;
551     if (blendFramebuffer) {
552         shader.append(gFS_Header_Extension_FramebufferFetch);
553     }
554     if (description.hasExternalTexture) {
555         shader.append(gFS_Header_Extension_ExternalTexture);
556     }
557 
558     shader.append(gFS_Header);
559 
560     // Varyings
561     if (description.hasTexture || description.hasExternalTexture) {
562         shader.append(gVS_Header_Varyings_HasTexture);
563     }
564     if (description.hasVertexAlpha) {
565         shader.append(gVS_Header_Varyings_HasVertexAlpha);
566     }
567     if (description.hasColors) {
568         shader.append(gVS_Header_Varyings_HasColors);
569     }
570     if (description.hasGradient) {
571         shader.append(gVS_Header_Varyings_HasGradient[gradientIndex(description)]);
572     }
573     if (description.hasBitmap) {
574         shader.append(gVS_Header_Varyings_HasBitmap);
575     }
576     if (description.hasRoundRectClip) {
577         shader.append(gVS_Header_Varyings_HasRoundRectClip);
578     }
579 
580     // Uniforms
581     int modulateOp = MODULATE_OP_NO_MODULATE;
582     const bool singleColor = !description.hasTexture && !description.hasExternalTexture &&
583             !description.hasGradient && !description.hasBitmap;
584 
585     if (description.modulate || singleColor) {
586         shader.append(gFS_Uniforms_Color);
587         if (!singleColor) modulateOp = MODULATE_OP_MODULATE;
588     }
589     if (description.hasTexture) {
590         shader.append(gFS_Uniforms_TextureSampler);
591     } else if (description.hasExternalTexture) {
592         shader.append(gFS_Uniforms_ExternalTextureSampler);
593     }
594     if (description.hasGradient) {
595         shader.appendFormat(gFS_Uniforms_GradientSampler[description.isSimpleGradient],
596                 gFS_Uniforms_Dither);
597     }
598     if (description.hasGammaCorrection) {
599         shader.append(gFS_Uniforms_Gamma);
600     }
601     if (description.hasRoundRectClip) {
602         shader.append(gFS_Uniforms_HasRoundRectClip);
603     }
604 
605     // Optimization for common cases
606     if (!description.hasVertexAlpha
607             && !blendFramebuffer
608             && !description.hasColors
609             && description.colorOp == ProgramDescription::kColorNone
610             && !description.hasDebugHighlight
611             && !description.hasRoundRectClip) {
612         bool fast = false;
613 
614         const bool noShader = !description.hasGradient && !description.hasBitmap;
615         const bool singleTexture = (description.hasTexture || description.hasExternalTexture) &&
616                 !description.hasAlpha8Texture && noShader;
617         const bool singleA8Texture = description.hasTexture &&
618                 description.hasAlpha8Texture && noShader;
619         const bool singleGradient = !description.hasTexture && !description.hasExternalTexture &&
620                 description.hasGradient && !description.hasBitmap &&
621                 description.gradientType == ProgramDescription::kGradientLinear;
622 
623         if (singleColor) {
624             shader.append(gFS_Fast_SingleColor);
625             fast = true;
626         } else if (singleTexture) {
627             if (!description.modulate) {
628                 shader.append(gFS_Fast_SingleTexture);
629             } else {
630                 shader.append(gFS_Fast_SingleModulateTexture);
631             }
632             fast = true;
633         } else if (singleA8Texture) {
634             if (!description.modulate) {
635                 if (description.hasGammaCorrection) {
636                     shader.append(gFS_Fast_SingleA8Texture_ApplyGamma);
637                 } else {
638                     shader.append(gFS_Fast_SingleA8Texture);
639                 }
640             } else {
641                 if (description.hasGammaCorrection) {
642                     shader.append(gFS_Fast_SingleModulateA8Texture_ApplyGamma);
643                 } else {
644                     shader.append(gFS_Fast_SingleModulateA8Texture);
645                 }
646             }
647             fast = true;
648         } else if (singleGradient) {
649             if (!description.modulate) {
650                 shader.appendFormat(gFS_Fast_SingleGradient[description.isSimpleGradient],
651                         gFS_Main_Dither[mHasES3]);
652             } else {
653                 shader.appendFormat(gFS_Fast_SingleModulateGradient[description.isSimpleGradient],
654                         gFS_Main_Dither[mHasES3]);
655             }
656             fast = true;
657         }
658 
659         if (fast) {
660 #if DEBUG_PROGRAMS
661                 PROGRAM_LOGD("*** Fast case:\n");
662                 PROGRAM_LOGD("*** Generated fragment shader:\n\n");
663                 printLongString(shader);
664 #endif
665 
666             return shader;
667         }
668     }
669 
670     if (description.hasBitmap) {
671         shader.append(gFS_Uniforms_BitmapSampler);
672     }
673     shader.append(gFS_Uniforms_ColorOp[description.colorOp]);
674 
675     // Generate required functions
676     if (description.hasGradient && description.hasBitmap) {
677         generateBlend(shader, "blendShaders", description.shadersMode);
678     }
679     if (description.colorOp == ProgramDescription::kColorBlend) {
680         generateBlend(shader, "blendColors", description.colorMode);
681     }
682     if (blendFramebuffer) {
683         generateBlend(shader, "blendFramebuffer", description.framebufferMode);
684     }
685     if (description.isBitmapNpot) {
686         generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT);
687     }
688 
689     // Begin the shader
690     shader.append(gFS_Main); {
691         // Stores the result in fragColor directly
692         if (description.hasTexture || description.hasExternalTexture) {
693             if (description.hasAlpha8Texture) {
694                 if (!description.hasGradient && !description.hasBitmap) {
695                     shader.append(gFS_Main_FetchA8Texture[modulateOp * 2 +
696                                                           description.hasGammaCorrection]);
697                 }
698             } else {
699                 shader.append(gFS_Main_FetchTexture[modulateOp]);
700             }
701         } else {
702             if (!description.hasGradient && !description.hasBitmap) {
703                 shader.append(gFS_Main_FetchColor);
704             }
705         }
706         if (description.hasGradient) {
707             shader.append(gFS_Main_FetchGradient[gradientIndex(description)]);
708             shader.appendFormat(gFS_Main_AddDitherToGradient, gFS_Main_Dither[mHasES3]);
709         }
710         if (description.hasBitmap) {
711             if (!description.isBitmapNpot) {
712                 shader.append(gFS_Main_FetchBitmap);
713             } else {
714                 shader.append(gFS_Main_FetchBitmapNpot);
715             }
716         }
717         bool applyModulate = false;
718         // Case when we have two shaders set
719         if (description.hasGradient && description.hasBitmap) {
720             if (description.isBitmapFirst) {
721                 shader.append(gFS_Main_BlendShadersBG);
722             } else {
723                 shader.append(gFS_Main_BlendShadersGB);
724             }
725             applyModulate = shaderOp(description, shader, modulateOp,
726                     gFS_Main_BlendShaders_Modulate);
727         } else {
728             if (description.hasGradient) {
729                 applyModulate = shaderOp(description, shader, modulateOp,
730                         gFS_Main_GradientShader_Modulate);
731             } else if (description.hasBitmap) {
732                 applyModulate = shaderOp(description, shader, modulateOp,
733                         gFS_Main_BitmapShader_Modulate);
734             }
735         }
736 
737         if (description.modulate && applyModulate) {
738             shader.append(gFS_Main_ModulateColor);
739         }
740 
741         // Apply the color op if needed
742         shader.append(gFS_Main_ApplyColorOp[description.colorOp]);
743 
744         if (description.hasVertexAlpha) {
745             if (description.useShadowAlphaInterp) {
746                 shader.append(gFS_Main_ApplyVertexAlphaShadowInterp);
747             } else {
748                 shader.append(gFS_Main_ApplyVertexAlphaLinearInterp);
749             }
750         }
751 
752         // Output the fragment
753         if (!blendFramebuffer) {
754             shader.append(gFS_Main_FragColor);
755         } else {
756             shader.append(!description.swapSrcDst ?
757                     gFS_Main_FragColor_Blend : gFS_Main_FragColor_Blend_Swap);
758         }
759         if (description.hasColors) {
760             shader.append(gFS_Main_FragColor_HasColors);
761         }
762         if (description.hasRoundRectClip) {
763             shader.append(gFS_Main_FragColor_HasRoundRectClip);
764         }
765         if (description.hasDebugHighlight) {
766             shader.append(gFS_Main_DebugHighlight);
767         }
768     }
769     // End the shader
770     shader.append(gFS_Footer);
771 
772 #if DEBUG_PROGRAMS
773         PROGRAM_LOGD("*** Generated fragment shader:\n\n");
774         printLongString(shader);
775 #endif
776 
777     return shader;
778 }
779 
generateBlend(String8 & shader,const char * name,SkXfermode::Mode mode)780 void ProgramCache::generateBlend(String8& shader, const char* name, SkXfermode::Mode mode) {
781     shader.append("\nvec4 ");
782     shader.append(name);
783     shader.append("(vec4 src, vec4 dst) {\n");
784     shader.append("    ");
785     shader.append(gBlendOps[mode]);
786     shader.append("}\n");
787 }
788 
generateTextureWrap(String8 & shader,GLenum wrapS,GLenum wrapT)789 void ProgramCache::generateTextureWrap(String8& shader, GLenum wrapS, GLenum wrapT) {
790     shader.append("\nhighp vec2 wrap(highp vec2 texCoords) {\n");
791     if (wrapS == GL_MIRRORED_REPEAT) {
792         shader.append("    highp float xMod2 = mod(texCoords.x, 2.0);\n");
793         shader.append("    if (xMod2 > 1.0) xMod2 = 2.0 - xMod2;\n");
794     }
795     if (wrapT == GL_MIRRORED_REPEAT) {
796         shader.append("    highp float yMod2 = mod(texCoords.y, 2.0);\n");
797         shader.append("    if (yMod2 > 1.0) yMod2 = 2.0 - yMod2;\n");
798     }
799     shader.append("    return vec2(");
800     switch (wrapS) {
801         case GL_CLAMP_TO_EDGE:
802             shader.append("texCoords.x");
803             break;
804         case GL_REPEAT:
805             shader.append("mod(texCoords.x, 1.0)");
806             break;
807         case GL_MIRRORED_REPEAT:
808             shader.append("xMod2");
809             break;
810     }
811     shader.append(", ");
812     switch (wrapT) {
813         case GL_CLAMP_TO_EDGE:
814             shader.append("texCoords.y");
815             break;
816         case GL_REPEAT:
817             shader.append("mod(texCoords.y, 1.0)");
818             break;
819         case GL_MIRRORED_REPEAT:
820             shader.append("yMod2");
821             break;
822     }
823     shader.append(");\n");
824     shader.append("}\n");
825 }
826 
printLongString(const String8 & shader) const827 void ProgramCache::printLongString(const String8& shader) const {
828     ssize_t index = 0;
829     ssize_t lastIndex = 0;
830     const char* str = shader.string();
831     while ((index = shader.find("\n", index)) > -1) {
832         String8 line(str, index - lastIndex);
833         if (line.length() == 0) line.append("\n");
834         ALOGD("%s", line.string());
835         index++;
836         str += (index - lastIndex);
837         lastIndex = index;
838     }
839 }
840 
841 }; // namespace uirenderer
842 }; // namespace android
843