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