OSDN Git Service

am fd395ce7: am d0077829: am fb397cf8: (-s ours) Merge "Frameworks/base: Support...
[android-x86/frameworks-base.git] / libs / hwui / ProgramCache.cpp
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         "    fragColor *= (1.0 - cos(alpha)) / 2.0;\n";
244
245 const char* gFS_Main_FetchTexture[2] = {
246         // Don't modulate
247         "    fragColor = texture2D(baseSampler, outTexCoords);\n",
248         // Modulate
249         "    fragColor = color * texture2D(baseSampler, outTexCoords);\n"
250 };
251 const char* gFS_Main_FetchA8Texture[4] = {
252         // Don't modulate
253         "    fragColor = texture2D(baseSampler, outTexCoords);\n",
254         "    fragColor = texture2D(baseSampler, outTexCoords);\n",
255         // Modulate
256         "    fragColor = color * texture2D(baseSampler, outTexCoords).a;\n",
257         "    fragColor = color * pow(texture2D(baseSampler, outTexCoords).a, gamma);\n"
258 };
259 const char* gFS_Main_FetchGradient[6] = {
260         // Linear
261         "    vec4 gradientColor = texture2D(gradientSampler, linear);\n",
262
263         "    vec4 gradientColor = mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n",
264
265         // Circular
266         "    vec4 gradientColor = texture2D(gradientSampler, vec2(length(circular), 0.5));\n",
267
268         "    vec4 gradientColor = mix(startColor, endColor, clamp(length(circular), 0.0, 1.0));\n",
269
270         // Sweep
271         "    highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
272         "    vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n",
273
274         "    highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
275         "    vec4 gradientColor = mix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n"
276 };
277 const char* gFS_Main_FetchBitmap =
278         "    vec4 bitmapColor = texture2D(bitmapSampler, outBitmapTexCoords);\n";
279 const char* gFS_Main_FetchBitmapNpot =
280         "    vec4 bitmapColor = texture2D(bitmapSampler, wrap(outBitmapTexCoords));\n";
281 const char* gFS_Main_BlendShadersBG =
282         "    fragColor = blendShaders(gradientColor, bitmapColor)";
283 const char* gFS_Main_BlendShadersGB =
284         "    fragColor = blendShaders(bitmapColor, gradientColor)";
285 const char* gFS_Main_BlendShaders_Modulate[6] = {
286         // Don't modulate
287         ";\n",
288         ";\n",
289         // Modulate
290         " * color.a;\n",
291         " * color.a;\n",
292         // Modulate with alpha 8 texture
293         " * texture2D(baseSampler, outTexCoords).a;\n",
294         " * pow(texture2D(baseSampler, outTexCoords).a, gamma);\n"
295 };
296 const char* gFS_Main_GradientShader_Modulate[6] = {
297         // Don't modulate
298         "    fragColor = gradientColor;\n",
299         "    fragColor = gradientColor;\n",
300         // Modulate
301         "    fragColor = gradientColor * color.a;\n",
302         "    fragColor = gradientColor * color.a;\n",
303         // Modulate with alpha 8 texture
304         "    fragColor = gradientColor * texture2D(baseSampler, outTexCoords).a;\n",
305         "    fragColor = gradientColor * pow(texture2D(baseSampler, outTexCoords).a, gamma);\n"
306     };
307 const char* gFS_Main_BitmapShader_Modulate[6] = {
308         // Don't modulate
309         "    fragColor = bitmapColor;\n",
310         "    fragColor = bitmapColor;\n",
311         // Modulate
312         "    fragColor = bitmapColor * color.a;\n",
313         "    fragColor = bitmapColor * color.a;\n",
314         // Modulate with alpha 8 texture
315         "    fragColor = bitmapColor * texture2D(baseSampler, outTexCoords).a;\n",
316         "    fragColor = bitmapColor * pow(texture2D(baseSampler, outTexCoords).a, gamma);\n"
317     };
318 const char* gFS_Main_FragColor =
319         "    gl_FragColor = fragColor;\n";
320 const char* gFS_Main_FragColor_HasColors =
321         "    gl_FragColor *= outColors;\n";
322 const char* gFS_Main_FragColor_Blend =
323         "    gl_FragColor = blendFramebuffer(fragColor, gl_LastFragColor);\n";
324 const char* gFS_Main_FragColor_Blend_Swap =
325         "    gl_FragColor = blendFramebuffer(gl_LastFragColor, fragColor);\n";
326 const char* gFS_Main_ApplyColorOp[3] = {
327         // None
328         "",
329         // Matrix
330         "    fragColor.rgb /= (fragColor.a + 0.0019);\n" // un-premultiply
331         "    fragColor *= colorMatrix;\n"
332         "    fragColor += colorMatrixVector;\n"
333         "    fragColor.rgb *= (fragColor.a + 0.0019);\n", // re-premultiply
334         // PorterDuff
335         "    fragColor = blendColors(colorBlend, fragColor);\n"
336 };
337
338 // Note: LTRB -> xyzw
339 const char* gFS_Main_FragColor_HasRoundRectClip =
340         "    mediump vec2 fragToLT = roundRectInnerRectLTRB.xy - roundRectPos;\n"
341         "    mediump vec2 fragFromRB = roundRectPos - roundRectInnerRectLTRB.zw;\n"
342
343         // divide + multiply by 128 to avoid falling out of range in length() function
344         "    mediump vec2 dist = max(max(fragToLT, fragFromRB), vec2(0.0, 0.0)) / 128.0;\n"
345         "    mediump float linearDist = roundRectRadius - (length(dist) * 128.0);\n"
346         "    gl_FragColor *= clamp(linearDist, 0.0, 1.0);\n";
347
348 const char* gFS_Main_DebugHighlight =
349         "    gl_FragColor.rgb = vec3(0.0, gl_FragColor.a, 0.0);\n";
350 const char* gFS_Footer =
351         "}\n\n";
352
353 ///////////////////////////////////////////////////////////////////////////////
354 // PorterDuff snippets
355 ///////////////////////////////////////////////////////////////////////////////
356
357 const char* gBlendOps[18] = {
358         // Clear
359         "return vec4(0.0, 0.0, 0.0, 0.0);\n",
360         // Src
361         "return src;\n",
362         // Dst
363         "return dst;\n",
364         // SrcOver
365         "return src + dst * (1.0 - src.a);\n",
366         // DstOver
367         "return dst + src * (1.0 - dst.a);\n",
368         // SrcIn
369         "return src * dst.a;\n",
370         // DstIn
371         "return dst * src.a;\n",
372         // SrcOut
373         "return src * (1.0 - dst.a);\n",
374         // DstOut
375         "return dst * (1.0 - src.a);\n",
376         // SrcAtop
377         "return vec4(src.rgb * dst.a + (1.0 - src.a) * dst.rgb, dst.a);\n",
378         // DstAtop
379         "return vec4(dst.rgb * src.a + (1.0 - dst.a) * src.rgb, src.a);\n",
380         // Xor
381         "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb, "
382                 "src.a + dst.a - 2.0 * src.a * dst.a);\n",
383         // Plus
384         "return min(src + dst, 1.0);\n",
385         // Modulate
386         "return src * dst;\n",
387         // Screen
388         "return src + dst - src * dst;\n",
389         // Overlay
390         "return clamp(vec4(mix("
391                 "2.0 * src.rgb * dst.rgb + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), "
392                 "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), "
393                 "step(dst.a, 2.0 * dst.rgb)), "
394                 "src.a + dst.a - src.a * dst.a), 0.0, 1.0);\n",
395         // Darken
396         "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + "
397                 "min(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n",
398         // Lighten
399         "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + "
400                 "max(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n",
401 };
402
403 ///////////////////////////////////////////////////////////////////////////////
404 // Constructors/destructors
405 ///////////////////////////////////////////////////////////////////////////////
406
407 ProgramCache::ProgramCache(Extensions& extensions)
408         : mHasES3(extensions.getMajorGlVersion() >= 3) {
409 }
410
411 ProgramCache::~ProgramCache() {
412     clear();
413 }
414
415 ///////////////////////////////////////////////////////////////////////////////
416 // Cache management
417 ///////////////////////////////////////////////////////////////////////////////
418
419 void ProgramCache::clear() {
420     PROGRAM_LOGD("Clearing program cache");
421     mCache.clear();
422 }
423
424 Program* ProgramCache::get(const ProgramDescription& description) {
425     programid key = description.key();
426     if (key == (PROGRAM_KEY_TEXTURE | PROGRAM_KEY_A8_TEXTURE)) {
427         // program for A8, unmodulated, texture w/o shader (black text/path textures) is equivalent
428         // to standard texture program (bitmaps, patches). Consider them equivalent.
429         key = PROGRAM_KEY_TEXTURE;
430     }
431
432     auto iter = mCache.find(key);
433     Program* program = nullptr;
434     if (iter == mCache.end()) {
435         description.log("Could not find program");
436         program = generateProgram(description, key);
437         mCache[key] = std::unique_ptr<Program>(program);
438     } else {
439         program = iter->second.get();
440     }
441     return program;
442 }
443
444 ///////////////////////////////////////////////////////////////////////////////
445 // Program generation
446 ///////////////////////////////////////////////////////////////////////////////
447
448 Program* ProgramCache::generateProgram(const ProgramDescription& description, programid key) {
449     String8 vertexShader = generateVertexShader(description);
450     String8 fragmentShader = generateFragmentShader(description);
451
452     return new Program(description, vertexShader.string(), fragmentShader.string());
453 }
454
455 static inline size_t gradientIndex(const ProgramDescription& description) {
456     return description.gradientType * 2 + description.isSimpleGradient;
457 }
458
459 String8 ProgramCache::generateVertexShader(const ProgramDescription& description) {
460     // Add attributes
461     String8 shader(gVS_Header_Attributes);
462     if (description.hasTexture || description.hasExternalTexture) {
463         shader.append(gVS_Header_Attributes_TexCoords);
464     }
465     if (description.hasVertexAlpha) {
466         shader.append(gVS_Header_Attributes_VertexAlphaParameters);
467     }
468     if (description.hasColors) {
469         shader.append(gVS_Header_Attributes_Colors);
470     }
471     // Uniforms
472     shader.append(gVS_Header_Uniforms);
473     if (description.hasTextureTransform) {
474         shader.append(gVS_Header_Uniforms_TextureTransform);
475     }
476     if (description.hasGradient) {
477         shader.append(gVS_Header_Uniforms_HasGradient);
478     }
479     if (description.hasBitmap) {
480         shader.append(gVS_Header_Uniforms_HasBitmap);
481     }
482     if (description.hasRoundRectClip) {
483         shader.append(gVS_Header_Uniforms_HasRoundRectClip);
484     }
485     // Varyings
486     if (description.hasTexture || description.hasExternalTexture) {
487         shader.append(gVS_Header_Varyings_HasTexture);
488     }
489     if (description.hasVertexAlpha) {
490         shader.append(gVS_Header_Varyings_HasVertexAlpha);
491     }
492     if (description.hasColors) {
493         shader.append(gVS_Header_Varyings_HasColors);
494     }
495     if (description.hasGradient) {
496         shader.append(gVS_Header_Varyings_HasGradient[gradientIndex(description)]);
497     }
498     if (description.hasBitmap) {
499         shader.append(gVS_Header_Varyings_HasBitmap);
500     }
501     if (description.hasRoundRectClip) {
502         shader.append(gVS_Header_Varyings_HasRoundRectClip);
503     }
504
505     // Begin the shader
506     shader.append(gVS_Main); {
507         if (description.hasTextureTransform) {
508             shader.append(gVS_Main_OutTransformedTexCoords);
509         } else if (description.hasTexture || description.hasExternalTexture) {
510             shader.append(gVS_Main_OutTexCoords);
511         }
512         if (description.hasVertexAlpha) {
513             shader.append(gVS_Main_VertexAlpha);
514         }
515         if (description.hasColors) {
516             shader.append(gVS_Main_OutColors);
517         }
518         if (description.hasBitmap) {
519             shader.append(gVS_Main_OutBitmapTexCoords);
520         }
521         // Output transformed position
522         shader.append(gVS_Main_Position);
523         if (description.hasGradient) {
524             shader.append(gVS_Main_OutGradient[gradientIndex(description)]);
525         }
526         if (description.hasRoundRectClip) {
527             shader.append(gVS_Main_HasRoundRectClip);
528         }
529     }
530     // End the shader
531     shader.append(gVS_Footer);
532
533     PROGRAM_LOGD("*** Generated vertex shader:\n\n%s", shader.string());
534
535     return shader;
536 }
537
538 static bool shaderOp(const ProgramDescription& description, String8& shader,
539         const int modulateOp, const char** snippets) {
540     int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp;
541     op = op * 2 + description.hasGammaCorrection;
542     shader.append(snippets[op]);
543     return description.hasAlpha8Texture;
544 }
545
546 String8 ProgramCache::generateFragmentShader(const ProgramDescription& description) {
547     String8 shader;
548
549     const bool blendFramebuffer = description.framebufferMode >= SkXfermode::kPlus_Mode;
550     if (blendFramebuffer) {
551         shader.append(gFS_Header_Extension_FramebufferFetch);
552     }
553     if (description.hasExternalTexture) {
554         shader.append(gFS_Header_Extension_ExternalTexture);
555     }
556
557     shader.append(gFS_Header);
558
559     // Varyings
560     if (description.hasTexture || description.hasExternalTexture) {
561         shader.append(gVS_Header_Varyings_HasTexture);
562     }
563     if (description.hasVertexAlpha) {
564         shader.append(gVS_Header_Varyings_HasVertexAlpha);
565     }
566     if (description.hasColors) {
567         shader.append(gVS_Header_Varyings_HasColors);
568     }
569     if (description.hasGradient) {
570         shader.append(gVS_Header_Varyings_HasGradient[gradientIndex(description)]);
571     }
572     if (description.hasBitmap) {
573         shader.append(gVS_Header_Varyings_HasBitmap);
574     }
575     if (description.hasRoundRectClip) {
576         shader.append(gVS_Header_Varyings_HasRoundRectClip);
577     }
578
579     // Uniforms
580     int modulateOp = MODULATE_OP_NO_MODULATE;
581     const bool singleColor = !description.hasTexture && !description.hasExternalTexture &&
582             !description.hasGradient && !description.hasBitmap;
583
584     if (description.modulate || singleColor) {
585         shader.append(gFS_Uniforms_Color);
586         if (!singleColor) modulateOp = MODULATE_OP_MODULATE;
587     }
588     if (description.hasTexture) {
589         shader.append(gFS_Uniforms_TextureSampler);
590     } else if (description.hasExternalTexture) {
591         shader.append(gFS_Uniforms_ExternalTextureSampler);
592     }
593     if (description.hasGradient) {
594         shader.appendFormat(gFS_Uniforms_GradientSampler[description.isSimpleGradient],
595                 gFS_Uniforms_Dither);
596     }
597     if (description.hasGammaCorrection) {
598         shader.append(gFS_Uniforms_Gamma);
599     }
600     if (description.hasRoundRectClip) {
601         shader.append(gFS_Uniforms_HasRoundRectClip);
602     }
603
604     // Optimization for common cases
605     if (!description.hasVertexAlpha
606             && !blendFramebuffer
607             && !description.hasColors
608             && description.colorOp == ProgramDescription::kColorNone
609             && !description.hasDebugHighlight
610             && !description.hasRoundRectClip) {
611         bool fast = false;
612
613         const bool noShader = !description.hasGradient && !description.hasBitmap;
614         const bool singleTexture = (description.hasTexture || description.hasExternalTexture) &&
615                 !description.hasAlpha8Texture && noShader;
616         const bool singleA8Texture = description.hasTexture &&
617                 description.hasAlpha8Texture && noShader;
618         const bool singleGradient = !description.hasTexture && !description.hasExternalTexture &&
619                 description.hasGradient && !description.hasBitmap &&
620                 description.gradientType == ProgramDescription::kGradientLinear;
621
622         if (singleColor) {
623             shader.append(gFS_Fast_SingleColor);
624             fast = true;
625         } else if (singleTexture) {
626             if (!description.modulate) {
627                 shader.append(gFS_Fast_SingleTexture);
628             } else {
629                 shader.append(gFS_Fast_SingleModulateTexture);
630             }
631             fast = true;
632         } else if (singleA8Texture) {
633             if (!description.modulate) {
634                 if (description.hasGammaCorrection) {
635                     shader.append(gFS_Fast_SingleA8Texture_ApplyGamma);
636                 } else {
637                     shader.append(gFS_Fast_SingleA8Texture);
638                 }
639             } else {
640                 if (description.hasGammaCorrection) {
641                     shader.append(gFS_Fast_SingleModulateA8Texture_ApplyGamma);
642                 } else {
643                     shader.append(gFS_Fast_SingleModulateA8Texture);
644                 }
645             }
646             fast = true;
647         } else if (singleGradient) {
648             if (!description.modulate) {
649                 shader.appendFormat(gFS_Fast_SingleGradient[description.isSimpleGradient],
650                         gFS_Main_Dither[mHasES3]);
651             } else {
652                 shader.appendFormat(gFS_Fast_SingleModulateGradient[description.isSimpleGradient],
653                         gFS_Main_Dither[mHasES3]);
654             }
655             fast = true;
656         }
657
658         if (fast) {
659 #if DEBUG_PROGRAMS
660                 PROGRAM_LOGD("*** Fast case:\n");
661                 PROGRAM_LOGD("*** Generated fragment shader:\n\n");
662                 printLongString(shader);
663 #endif
664
665             return shader;
666         }
667     }
668
669     if (description.hasBitmap) {
670         shader.append(gFS_Uniforms_BitmapSampler);
671     }
672     shader.append(gFS_Uniforms_ColorOp[description.colorOp]);
673
674     // Generate required functions
675     if (description.hasGradient && description.hasBitmap) {
676         generateBlend(shader, "blendShaders", description.shadersMode);
677     }
678     if (description.colorOp == ProgramDescription::kColorBlend) {
679         generateBlend(shader, "blendColors", description.colorMode);
680     }
681     if (blendFramebuffer) {
682         generateBlend(shader, "blendFramebuffer", description.framebufferMode);
683     }
684     if (description.isBitmapNpot) {
685         generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT);
686     }
687
688     // Begin the shader
689     shader.append(gFS_Main); {
690         // Stores the result in fragColor directly
691         if (description.hasTexture || description.hasExternalTexture) {
692             if (description.hasAlpha8Texture) {
693                 if (!description.hasGradient && !description.hasBitmap) {
694                     shader.append(gFS_Main_FetchA8Texture[modulateOp * 2 +
695                                                           description.hasGammaCorrection]);
696                 }
697             } else {
698                 shader.append(gFS_Main_FetchTexture[modulateOp]);
699             }
700         } else {
701             if (!description.hasGradient && !description.hasBitmap) {
702                 shader.append(gFS_Main_FetchColor);
703             }
704         }
705         if (description.hasGradient) {
706             shader.append(gFS_Main_FetchGradient[gradientIndex(description)]);
707             shader.appendFormat(gFS_Main_AddDitherToGradient, gFS_Main_Dither[mHasES3]);
708         }
709         if (description.hasBitmap) {
710             if (!description.isBitmapNpot) {
711                 shader.append(gFS_Main_FetchBitmap);
712             } else {
713                 shader.append(gFS_Main_FetchBitmapNpot);
714             }
715         }
716         bool applyModulate = false;
717         // Case when we have two shaders set
718         if (description.hasGradient && description.hasBitmap) {
719             if (description.isBitmapFirst) {
720                 shader.append(gFS_Main_BlendShadersBG);
721             } else {
722                 shader.append(gFS_Main_BlendShadersGB);
723             }
724             applyModulate = shaderOp(description, shader, modulateOp,
725                     gFS_Main_BlendShaders_Modulate);
726         } else {
727             if (description.hasGradient) {
728                 applyModulate = shaderOp(description, shader, modulateOp,
729                         gFS_Main_GradientShader_Modulate);
730             } else if (description.hasBitmap) {
731                 applyModulate = shaderOp(description, shader, modulateOp,
732                         gFS_Main_BitmapShader_Modulate);
733             }
734         }
735
736         if (description.modulate && applyModulate) {
737             shader.append(gFS_Main_ModulateColor);
738         }
739
740         // Apply the color op if needed
741         shader.append(gFS_Main_ApplyColorOp[description.colorOp]);
742
743         if (description.hasVertexAlpha) {
744             if (description.useShadowAlphaInterp) {
745                 shader.append(gFS_Main_ApplyVertexAlphaShadowInterp);
746             } else {
747                 shader.append(gFS_Main_ApplyVertexAlphaLinearInterp);
748             }
749         }
750
751         // Output the fragment
752         if (!blendFramebuffer) {
753             shader.append(gFS_Main_FragColor);
754         } else {
755             shader.append(!description.swapSrcDst ?
756                     gFS_Main_FragColor_Blend : gFS_Main_FragColor_Blend_Swap);
757         }
758         if (description.hasColors) {
759             shader.append(gFS_Main_FragColor_HasColors);
760         }
761         if (description.hasRoundRectClip) {
762             shader.append(gFS_Main_FragColor_HasRoundRectClip);
763         }
764         if (description.hasDebugHighlight) {
765             shader.append(gFS_Main_DebugHighlight);
766         }
767     }
768     // End the shader
769     shader.append(gFS_Footer);
770
771 #if DEBUG_PROGRAMS
772         PROGRAM_LOGD("*** Generated fragment shader:\n\n");
773         printLongString(shader);
774 #endif
775
776     return shader;
777 }
778
779 void ProgramCache::generateBlend(String8& shader, const char* name, SkXfermode::Mode mode) {
780     shader.append("\nvec4 ");
781     shader.append(name);
782     shader.append("(vec4 src, vec4 dst) {\n");
783     shader.append("    ");
784     shader.append(gBlendOps[mode]);
785     shader.append("}\n");
786 }
787
788 void ProgramCache::generateTextureWrap(String8& shader, GLenum wrapS, GLenum wrapT) {
789     shader.append("\nhighp vec2 wrap(highp vec2 texCoords) {\n");
790     if (wrapS == GL_MIRRORED_REPEAT) {
791         shader.append("    highp float xMod2 = mod(texCoords.x, 2.0);\n");
792         shader.append("    if (xMod2 > 1.0) xMod2 = 2.0 - xMod2;\n");
793     }
794     if (wrapT == GL_MIRRORED_REPEAT) {
795         shader.append("    highp float yMod2 = mod(texCoords.y, 2.0);\n");
796         shader.append("    if (yMod2 > 1.0) yMod2 = 2.0 - yMod2;\n");
797     }
798     shader.append("    return vec2(");
799     switch (wrapS) {
800         case GL_CLAMP_TO_EDGE:
801             shader.append("texCoords.x");
802             break;
803         case GL_REPEAT:
804             shader.append("mod(texCoords.x, 1.0)");
805             break;
806         case GL_MIRRORED_REPEAT:
807             shader.append("xMod2");
808             break;
809     }
810     shader.append(", ");
811     switch (wrapT) {
812         case GL_CLAMP_TO_EDGE:
813             shader.append("texCoords.y");
814             break;
815         case GL_REPEAT:
816             shader.append("mod(texCoords.y, 1.0)");
817             break;
818         case GL_MIRRORED_REPEAT:
819             shader.append("yMod2");
820             break;
821     }
822     shader.append(");\n");
823     shader.append("}\n");
824 }
825
826 void ProgramCache::printLongString(const String8& shader) const {
827     ssize_t index = 0;
828     ssize_t lastIndex = 0;
829     const char* str = shader.string();
830     while ((index = shader.find("\n", index)) > -1) {
831         String8 line(str, index - lastIndex);
832         if (line.length() == 0) line.append("\n");
833         ALOGD("%s", line.string());
834         index++;
835         str += (index - lastIndex);
836         lastIndex = index;
837     }
838 }
839
840 }; // namespace uirenderer
841 }; // namespace android