ProgramCache.cpp revision b48800428906ae455c2b63acacd44e390e1fee49
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).r"
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_Footer =
346        "}\n\n";
347
348///////////////////////////////////////////////////////////////////////////////
349// PorterDuff snippets
350///////////////////////////////////////////////////////////////////////////////
351
352const char* gBlendOps[18] = {
353        // Clear
354        "return vec4(0.0, 0.0, 0.0, 0.0);\n",
355        // Src
356        "return src;\n",
357        // Dst
358        "return dst;\n",
359        // SrcOver
360        "return src + dst * (1.0 - src.a);\n",
361        // DstOver
362        "return dst + src * (1.0 - dst.a);\n",
363        // SrcIn
364        "return src * dst.a;\n",
365        // DstIn
366        "return dst * src.a;\n",
367        // SrcOut
368        "return src * (1.0 - dst.a);\n",
369        // DstOut
370        "return dst * (1.0 - src.a);\n",
371        // SrcAtop
372        "return vec4(src.rgb * dst.a + (1.0 - src.a) * dst.rgb, dst.a);\n",
373        // DstAtop
374        "return vec4(dst.rgb * src.a + (1.0 - dst.a) * src.rgb, src.a);\n",
375        // Xor
376        "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb, "
377                "src.a + dst.a - 2.0 * src.a * dst.a);\n",
378        // Add
379        "return min(src + dst, 1.0);\n",
380        // Multiply
381        "return src * dst;\n",
382        // Screen
383        "return src + dst - src * dst;\n",
384        // Overlay
385        "return clamp(vec4(mix("
386                "2.0 * src.rgb * dst.rgb + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), "
387                "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), "
388                "step(dst.a, 2.0 * dst.rgb)), "
389                "src.a + dst.a - src.a * dst.a), 0.0, 1.0);\n",
390        // Darken
391        "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + "
392                "min(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n",
393        // Lighten
394        "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + "
395                "max(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n",
396};
397
398///////////////////////////////////////////////////////////////////////////////
399// Constructors/destructors
400///////////////////////////////////////////////////////////////////////////////
401
402ProgramCache::ProgramCache(): mHasES3(Extensions::getInstance().getMajorGlVersion() >= 3) {
403}
404
405ProgramCache::~ProgramCache() {
406    clear();
407}
408
409///////////////////////////////////////////////////////////////////////////////
410// Cache management
411///////////////////////////////////////////////////////////////////////////////
412
413void ProgramCache::clear() {
414    PROGRAM_LOGD("Clearing program cache");
415
416    size_t count = mCache.size();
417    for (size_t i = 0; i < count; i++) {
418        delete mCache.valueAt(i);
419    }
420    mCache.clear();
421}
422
423Program* ProgramCache::get(const ProgramDescription& description) {
424    programid key = description.key();
425    if (key == (PROGRAM_KEY_TEXTURE | PROGRAM_KEY_A8_TEXTURE)) {
426        // program for A8, unmodulated, texture w/o shader (black text/path textures) is equivalent
427        // to standard texture program (bitmaps, patches). Consider them equivalent.
428        key = PROGRAM_KEY_TEXTURE;
429    }
430
431    ssize_t index = mCache.indexOfKey(key);
432    Program* program = NULL;
433    if (index < 0) {
434        description.log("Could not find program");
435        program = generateProgram(description, key);
436        mCache.add(key, program);
437    } else {
438        program = mCache.valueAt(index);
439    }
440    return program;
441}
442
443///////////////////////////////////////////////////////////////////////////////
444// Program generation
445///////////////////////////////////////////////////////////////////////////////
446
447Program* ProgramCache::generateProgram(const ProgramDescription& description, programid key) {
448    String8 vertexShader = generateVertexShader(description);
449    String8 fragmentShader = generateFragmentShader(description);
450
451    return new Program(description, vertexShader.string(), fragmentShader.string());
452}
453
454static inline size_t gradientIndex(const ProgramDescription& description) {
455    return description.gradientType * 2 + description.isSimpleGradient;
456}
457
458String8 ProgramCache::generateVertexShader(const ProgramDescription& description) {
459    // Add attributes
460    String8 shader(gVS_Header_Attributes);
461    if (description.hasTexture || description.hasExternalTexture) {
462        shader.append(gVS_Header_Attributes_TexCoords);
463    }
464    if (description.isAA) {
465        shader.append(gVS_Header_Attributes_AAVertexShapeParameters);
466    }
467    if (description.hasColors) {
468        shader.append(gVS_Header_Attributes_Colors);
469    }
470    // Uniforms
471    shader.append(gVS_Header_Uniforms);
472    if (description.hasTextureTransform) {
473        shader.append(gVS_Header_Uniforms_TextureTransform);
474    }
475    if (description.hasGradient) {
476        shader.append(gVS_Header_Uniforms_HasGradient);
477    }
478    if (description.hasBitmap) {
479        shader.append(gVS_Header_Uniforms_HasBitmap);
480    }
481    if (description.isPoint) {
482        shader.append(gVS_Header_Uniforms_IsPoint);
483    }
484    // Varyings
485    if (description.hasTexture || description.hasExternalTexture) {
486        shader.append(gVS_Header_Varyings_HasTexture);
487    }
488    if (description.isAA) {
489        shader.append(gVS_Header_Varyings_IsAAVertexShape);
490    }
491    if (description.hasColors) {
492        shader.append(gVS_Header_Varyings_HasColors);
493    }
494    if (description.hasGradient) {
495        shader.append(gVS_Header_Varyings_HasGradient[gradientIndex(description)]);
496    }
497    if (description.hasBitmap) {
498        shader.append(description.isPoint ?
499                gVS_Header_Varyings_PointHasBitmap :
500                gVS_Header_Varyings_HasBitmap);
501    }
502
503    // Begin the shader
504    shader.append(gVS_Main); {
505        if (description.hasTextureTransform) {
506            shader.append(gVS_Main_OutTransformedTexCoords);
507        } else if (description.hasTexture || description.hasExternalTexture) {
508            shader.append(gVS_Main_OutTexCoords);
509        }
510        if (description.isAA) {
511            shader.append(gVS_Main_AAVertexShape);
512        }
513        if (description.hasColors) {
514            shader.append(gVS_Main_OutColors);
515        }
516        if (description.hasBitmap) {
517            shader.append(description.isPoint ?
518                    gVS_Main_OutPointBitmapTexCoords :
519                    gVS_Main_OutBitmapTexCoords);
520        }
521        if (description.isPoint) {
522            shader.append(gVS_Main_PointSize);
523        }
524        // Output transformed position
525        shader.append(gVS_Main_Position);
526        if (description.hasGradient) {
527            shader.append(gVS_Main_OutGradient[gradientIndex(description)]);
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
538static 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
546String8 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.isAA) {
564        shader.append(gVS_Header_Varyings_IsAAVertexShape);
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(description.isPoint ?
574                gVS_Header_Varyings_PointHasBitmap :
575                gVS_Header_Varyings_HasBitmap);
576    }
577
578    // Uniforms
579    int modulateOp = MODULATE_OP_NO_MODULATE;
580    const bool singleColor = !description.hasTexture && !description.hasExternalTexture &&
581            !description.hasGradient && !description.hasBitmap;
582
583    if (description.modulate || singleColor) {
584        shader.append(gFS_Uniforms_Color);
585        if (!singleColor) modulateOp = MODULATE_OP_MODULATE;
586    }
587    if (description.hasTexture) {
588        shader.append(gFS_Uniforms_TextureSampler);
589    } else if (description.hasExternalTexture) {
590        shader.append(gFS_Uniforms_ExternalTextureSampler);
591    }
592    if (description.hasGradient) {
593        shader.appendFormat(gFS_Uniforms_GradientSampler[description.isSimpleGradient],
594                gFS_Uniforms_Dither);
595    }
596    if (description.hasBitmap && description.isPoint) {
597        shader.append(gFS_Header_Uniforms_PointHasBitmap);
598    }
599    if (description.hasGammaCorrection) {
600        shader.append(gFS_Uniforms_Gamma);
601    }
602
603    // Optimization for common cases
604    if (!description.isAA && !blendFramebuffer && !description.hasColors &&
605            description.colorOp == ProgramDescription::kColorNone &&
606            !description.isPoint && !description.hasDebugHighlight) {
607        bool fast = false;
608
609        const bool noShader = !description.hasGradient && !description.hasBitmap;
610        const bool singleTexture = (description.hasTexture || description.hasExternalTexture) &&
611                !description.hasAlpha8Texture && noShader;
612        const bool singleA8Texture = description.hasTexture &&
613                description.hasAlpha8Texture && noShader;
614        const bool singleGradient = !description.hasTexture && !description.hasExternalTexture &&
615                description.hasGradient && !description.hasBitmap &&
616                description.gradientType == ProgramDescription::kGradientLinear;
617
618        if (singleColor) {
619            shader.append(gFS_Fast_SingleColor);
620            fast = true;
621        } else if (singleTexture) {
622            if (!description.modulate) {
623                shader.append(gFS_Fast_SingleTexture);
624            } else {
625                shader.append(gFS_Fast_SingleModulateTexture);
626            }
627            fast = true;
628        } else if (singleA8Texture) {
629            if (!description.modulate) {
630                if (description.hasGammaCorrection) {
631                    shader.append(gFS_Fast_SingleA8Texture_ApplyGamma);
632                } else {
633                    shader.append(gFS_Fast_SingleA8Texture);
634                }
635            } else {
636                if (description.hasGammaCorrection) {
637                    shader.append(gFS_Fast_SingleModulateA8Texture_ApplyGamma);
638                } else {
639                    shader.append(gFS_Fast_SingleModulateA8Texture);
640                }
641            }
642            fast = true;
643        } else if (singleGradient) {
644            if (!description.modulate) {
645                shader.appendFormat(gFS_Fast_SingleGradient[description.isSimpleGradient],
646                        gFS_Main_Dither[mHasES3]);
647            } else {
648                shader.appendFormat(gFS_Fast_SingleModulateGradient[description.isSimpleGradient],
649                        gFS_Main_Dither[mHasES3]);
650            }
651            fast = true;
652        }
653
654        if (fast) {
655#if DEBUG_PROGRAMS
656                PROGRAM_LOGD("*** Fast case:\n");
657                PROGRAM_LOGD("*** Generated fragment shader:\n\n");
658                printLongString(shader);
659#endif
660
661            return shader;
662        }
663    }
664
665    if (description.hasBitmap) {
666        shader.append(gFS_Uniforms_BitmapSampler);
667    }
668    shader.append(gFS_Uniforms_ColorOp[description.colorOp]);
669
670    // Generate required functions
671    if (description.hasGradient && description.hasBitmap) {
672        generateBlend(shader, "blendShaders", description.shadersMode);
673    }
674    if (description.colorOp == ProgramDescription::kColorBlend) {
675        generateBlend(shader, "blendColors", description.colorMode);
676    }
677    if (blendFramebuffer) {
678        generateBlend(shader, "blendFramebuffer", description.framebufferMode);
679    }
680    if (description.isBitmapNpot) {
681        generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT);
682    }
683
684    // Begin the shader
685    shader.append(gFS_Main); {
686        // Stores the result in fragColor directly
687        if (description.hasTexture || description.hasExternalTexture) {
688            if (description.hasAlpha8Texture) {
689                if (!description.hasGradient && !description.hasBitmap) {
690                    shader.append(gFS_Main_FetchA8Texture[modulateOp * 2 +
691                                                          description.hasGammaCorrection]);
692                }
693            } else {
694                shader.append(gFS_Main_FetchTexture[modulateOp]);
695            }
696        } else {
697            if (!description.hasGradient && !description.hasBitmap) {
698                shader.append(gFS_Main_FetchColor);
699            }
700        }
701        if (description.hasGradient) {
702            shader.append(gFS_Main_FetchGradient[gradientIndex(description)]);
703            shader.appendFormat(gFS_Main_AddDitherToGradient, gFS_Main_Dither[mHasES3]);
704        }
705        if (description.hasBitmap) {
706            if (description.isPoint) {
707                shader.append(gFS_Main_PointBitmapTexCoords);
708            }
709            if (!description.isBitmapNpot) {
710                shader.append(gFS_Main_FetchBitmap);
711            } else {
712                shader.append(gFS_Main_FetchBitmapNpot);
713            }
714        }
715        bool applyModulate = false;
716        // Case when we have two shaders set
717        if (description.hasGradient && description.hasBitmap) {
718            if (description.isBitmapFirst) {
719                shader.append(gFS_Main_BlendShadersBG);
720            } else {
721                shader.append(gFS_Main_BlendShadersGB);
722            }
723            applyModulate = shaderOp(description, shader, modulateOp,
724                    gFS_Main_BlendShaders_Modulate);
725        } else {
726            if (description.hasGradient) {
727                applyModulate = shaderOp(description, shader, modulateOp,
728                        gFS_Main_GradientShader_Modulate);
729            } else if (description.hasBitmap) {
730                applyModulate = shaderOp(description, shader, modulateOp,
731                        gFS_Main_BitmapShader_Modulate);
732            }
733        }
734
735        if (description.modulate && applyModulate) {
736            shader.append(gFS_Main_ModulateColor);
737        }
738
739        // Apply the color op if needed
740        shader.append(gFS_Main_ApplyColorOp[description.colorOp]);
741
742        if (description.isAA) {
743            shader.append(gFS_Main_AccountForAAVertexShape);
744        }
745
746        // Output the fragment
747        if (!blendFramebuffer) {
748            shader.append(gFS_Main_FragColor);
749        } else {
750            shader.append(!description.swapSrcDst ?
751                    gFS_Main_FragColor_Blend : gFS_Main_FragColor_Blend_Swap);
752        }
753        if (description.hasColors) {
754            shader.append(gFS_Main_FragColor_HasColors);
755        }
756        if (description.hasDebugHighlight) {
757            shader.append(gFS_Main_DebugHighlight);
758        }
759    }
760    // End the shader
761    shader.append(gFS_Footer);
762
763#if DEBUG_PROGRAMS
764        PROGRAM_LOGD("*** Generated fragment shader:\n\n");
765        printLongString(shader);
766#endif
767
768    return shader;
769}
770
771void ProgramCache::generateBlend(String8& shader, const char* name, SkXfermode::Mode mode) {
772    shader.append("\nvec4 ");
773    shader.append(name);
774    shader.append("(vec4 src, vec4 dst) {\n");
775    shader.append("    ");
776    shader.append(gBlendOps[mode]);
777    shader.append("}\n");
778}
779
780void ProgramCache::generateTextureWrap(String8& shader, GLenum wrapS, GLenum wrapT) {
781    shader.append("\nhighp vec2 wrap(highp vec2 texCoords) {\n");
782    if (wrapS == GL_MIRRORED_REPEAT) {
783        shader.append("    highp float xMod2 = mod(texCoords.x, 2.0);\n");
784        shader.append("    if (xMod2 > 1.0) xMod2 = 2.0 - xMod2;\n");
785    }
786    if (wrapT == GL_MIRRORED_REPEAT) {
787        shader.append("    highp float yMod2 = mod(texCoords.y, 2.0);\n");
788        shader.append("    if (yMod2 > 1.0) yMod2 = 2.0 - yMod2;\n");
789    }
790    shader.append("    return vec2(");
791    switch (wrapS) {
792        case GL_CLAMP_TO_EDGE:
793            shader.append("texCoords.x");
794            break;
795        case GL_REPEAT:
796            shader.append("mod(texCoords.x, 1.0)");
797            break;
798        case GL_MIRRORED_REPEAT:
799            shader.append("xMod2");
800            break;
801    }
802    shader.append(", ");
803    switch (wrapT) {
804        case GL_CLAMP_TO_EDGE:
805            shader.append("texCoords.y");
806            break;
807        case GL_REPEAT:
808            shader.append("mod(texCoords.y, 1.0)");
809            break;
810        case GL_MIRRORED_REPEAT:
811            shader.append("yMod2");
812            break;
813    }
814    shader.append(");\n");
815    shader.append("}\n");
816}
817
818void ProgramCache::printLongString(const String8& shader) const {
819    ssize_t index = 0;
820    ssize_t lastIndex = 0;
821    const char* str = shader.string();
822    while ((index = shader.find("\n", index)) > -1) {
823        String8 line(str, index - lastIndex);
824        if (line.length() == 0) line.append("\n");
825        PROGRAM_LOGD("%s", line.string());
826        index++;
827        str += (index - lastIndex);
828        lastIndex = index;
829    }
830}
831
832}; // namespace uirenderer
833}; // namespace android
834