ProgramCache.cpp revision 63553478130f78d44c8fbeaebc610e19925544a5
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 "ProgramCache.h"
23
24namespace android {
25namespace uirenderer {
26
27///////////////////////////////////////////////////////////////////////////////
28// Defines
29///////////////////////////////////////////////////////////////////////////////
30
31#define MODULATE_OP_NO_MODULATE 0
32#define MODULATE_OP_MODULATE 1
33#define MODULATE_OP_MODULATE_A8 2
34
35///////////////////////////////////////////////////////////////////////////////
36// Vertex shaders snippets
37///////////////////////////////////////////////////////////////////////////////
38
39const char* gVS_Header_Attributes =
40        "attribute vec4 position;\n";
41const char* gVS_Header_Attributes_TexCoords =
42        "attribute vec2 texCoords;\n";
43const char* gVS_Header_Attributes_AAParameters =
44        "attribute float vtxWidth;\n"
45        "attribute float vtxLength;\n";
46const char* gVS_Header_Uniforms_TextureTransform =
47        "uniform mat4 mainTextureTransform;\n";
48const char* gVS_Header_Uniforms =
49        "uniform mat4 transform;\n";
50const char* gVS_Header_Uniforms_IsPoint =
51        "uniform mediump float pointSize;\n";
52const char* gVS_Header_Uniforms_HasGradient[3] = {
53        // Linear
54        "uniform mat4 screenSpace;\n",
55        // Circular
56        "uniform mat4 screenSpace;\n",
57        // Sweep
58        "uniform mat4 screenSpace;\n"
59};
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_IsAA =
66        "varying float widthProportion;\n"
67        "varying float lengthProportion;\n";
68const char* gVS_Header_Varyings_HasBitmap =
69        "varying highp vec2 outBitmapTexCoords;\n";
70const char* gVS_Header_Varyings_PointHasBitmap =
71        "varying highp vec2 outPointBitmapTexCoords;\n";
72// TODO: These values are used to sample from textures,
73//       they may need to be highp
74const char* gVS_Header_Varyings_HasGradient[3] = {
75        // Linear
76        "varying highp vec2 linear;\n",
77        // Circular
78        "varying highp vec2 circular;\n",
79        // Sweep
80        "varying highp vec2 sweep;\n"
81};
82const char* gVS_Main =
83        "\nvoid main(void) {\n";
84const char* gVS_Main_OutTexCoords =
85        "    outTexCoords = texCoords;\n";
86const char* gVS_Main_OutTransformedTexCoords =
87        "    outTexCoords = (mainTextureTransform * vec4(texCoords, 0.0, 1.0)).xy;\n";
88const char* gVS_Main_OutGradient[3] = {
89        // Linear
90        "    linear = vec2((screenSpace * position).x, 0.5);\n",
91        // Circular
92        "    circular = (screenSpace * position).xy;\n",
93        // Sweep
94        "    sweep = (screenSpace * position).xy;\n"
95};
96const char* gVS_Main_OutBitmapTexCoords =
97        "    outBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n";
98const char* gVS_Main_OutPointBitmapTexCoords =
99        "    outPointBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n";
100const char* gVS_Main_Position =
101        "    gl_Position = transform * position;\n";
102const char* gVS_Main_PointSize =
103        "    gl_PointSize = pointSize;\n";
104const char* gVS_Main_AA =
105        "    widthProportion = vtxWidth;\n"
106        "    lengthProportion = vtxLength;\n";
107const char* gVS_Footer =
108        "}\n\n";
109
110///////////////////////////////////////////////////////////////////////////////
111// Fragment shaders snippets
112///////////////////////////////////////////////////////////////////////////////
113
114const char* gFS_Header_Extension_FramebufferFetch =
115        "#extension GL_NV_shader_framebuffer_fetch : enable\n\n";
116const char* gFS_Header_Extension_ExternalTexture =
117        "#extension GL_OES_EGL_image_external : require\n\n";
118const char* gFS_Header =
119        "precision mediump float;\n\n";
120const char* gFS_Uniforms_Color =
121        "uniform vec4 color;\n";
122const char* gFS_Uniforms_AA =
123        "uniform float boundaryWidth;\n"
124        "uniform float inverseBoundaryWidth;\n"
125        "uniform float boundaryLength;\n"
126        "uniform float inverseBoundaryLength;\n";
127const char* gFS_Header_Uniforms_PointHasBitmap =
128        "uniform vec2 textureDimension;\n"
129        "uniform float pointSize;\n";
130const char* gFS_Uniforms_TextureSampler =
131        "uniform sampler2D sampler;\n";
132const char* gFS_Uniforms_ExternalTextureSampler =
133        "uniform samplerExternalOES sampler;\n";
134const char* gFS_Uniforms_GradientSampler[3] = {
135        // Linear
136        "uniform sampler2D gradientSampler;\n",
137        // Circular
138        "uniform sampler2D gradientSampler;\n",
139        // Sweep
140        "uniform sampler2D gradientSampler;\n"
141};
142const char* gFS_Uniforms_BitmapSampler =
143        "uniform sampler2D bitmapSampler;\n";
144const char* gFS_Uniforms_ColorOp[4] = {
145        // None
146        "",
147        // Matrix
148        "uniform mat4 colorMatrix;\n"
149        "uniform vec4 colorMatrixVector;\n",
150        // Lighting
151        "uniform vec4 lightingMul;\n"
152        "uniform vec4 lightingAdd;\n",
153        // PorterDuff
154        "uniform vec4 colorBlend;\n"
155};
156const char* gFS_Uniforms_Gamma =
157        "uniform float gamma;\n";
158
159const char* gFS_Main =
160        "\nvoid main(void) {\n"
161        "    lowp vec4 fragColor;\n";
162
163const char* gFS_Main_PointBitmapTexCoords =
164        "    highp vec2 outBitmapTexCoords = outPointBitmapTexCoords + "
165        "((gl_PointCoord - vec2(0.5, 0.5)) * textureDimension * vec2(pointSize, pointSize));\n";
166
167// Fast cases
168const char* gFS_Fast_SingleColor =
169        "\nvoid main(void) {\n"
170        "    gl_FragColor = color;\n"
171        "}\n\n";
172const char* gFS_Fast_SingleTexture =
173        "\nvoid main(void) {\n"
174        "    gl_FragColor = texture2D(sampler, outTexCoords);\n"
175        "}\n\n";
176const char* gFS_Fast_SingleModulateTexture =
177        "\nvoid main(void) {\n"
178        "    gl_FragColor = color.a * texture2D(sampler, outTexCoords);\n"
179        "}\n\n";
180const char* gFS_Fast_SingleA8Texture =
181        "\nvoid main(void) {\n"
182        "    gl_FragColor = texture2D(sampler, outTexCoords);\n"
183        "}\n\n";
184const char* gFS_Fast_SingleA8Texture_ApplyGamma =
185        "\nvoid main(void) {\n"
186        "    gl_FragColor = vec4(0.0, 0.0, 0.0, pow(texture2D(sampler, outTexCoords).a, gamma));\n"
187        "}\n\n";
188const char* gFS_Fast_SingleModulateA8Texture =
189        "\nvoid main(void) {\n"
190        "    gl_FragColor = color * texture2D(sampler, outTexCoords).a;\n"
191        "}\n\n";
192const char* gFS_Fast_SingleModulateA8Texture_ApplyGamma =
193        "\nvoid main(void) {\n"
194        "    gl_FragColor = color * pow(texture2D(sampler, outTexCoords).a, gamma);\n"
195        "}\n\n";
196const char* gFS_Fast_SingleGradient =
197        "\nvoid main(void) {\n"
198        "    gl_FragColor = texture2D(gradientSampler, linear);\n"
199        "}\n\n";
200const char* gFS_Fast_SingleModulateGradient =
201        "\nvoid main(void) {\n"
202        "    gl_FragColor = color.a * texture2D(gradientSampler, linear);\n"
203        "}\n\n";
204
205// General case
206const char* gFS_Main_FetchColor =
207        "    fragColor = color;\n";
208const char* gFS_Main_ModulateColor =
209        "    fragColor *= color.a;\n";
210const char* gFS_Main_ModulateColor_ApplyGamma =
211        "    fragColor *= pow(color.a, gamma);\n";
212const char* gFS_Main_AccountForAA =
213        "    if (widthProportion < boundaryWidth) {\n"
214        "        fragColor *= (widthProportion * inverseBoundaryWidth);\n"
215        "    } else if (widthProportion > (1.0 - boundaryWidth)) {\n"
216        "        fragColor *= ((1.0 - widthProportion) * inverseBoundaryWidth);\n"
217        "    }\n"
218        "    if (lengthProportion < boundaryLength) {\n"
219        "        fragColor *= (lengthProportion * inverseBoundaryLength);\n"
220        "    } else if (lengthProportion > (1.0 - boundaryLength)) {\n"
221        "        fragColor *= ((1.0 - lengthProportion) * inverseBoundaryLength);\n"
222        "    }\n";
223const char* gFS_Main_FetchTexture[2] = {
224        // Don't modulate
225        "    fragColor = texture2D(sampler, outTexCoords);\n",
226        // Modulate
227        "    fragColor = color * texture2D(sampler, outTexCoords);\n"
228};
229const char* gFS_Main_FetchA8Texture[2] = {
230        // Don't modulate
231        "    fragColor = texture2D(sampler, outTexCoords);\n",
232        // Modulate
233        "    fragColor = color * texture2D(sampler, outTexCoords).a;\n"
234};
235const char* gFS_Main_FetchGradient[3] = {
236        // Linear
237        "    vec4 gradientColor = texture2D(gradientSampler, linear);\n",
238        // Circular
239        "    highp float index = length(circular);\n"
240        "    vec4 gradientColor = texture2D(gradientSampler, vec2(index, 0.5));\n",
241        // Sweep
242        "    highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
243        "    vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n"
244};
245const char* gFS_Main_FetchBitmap =
246        "    vec4 bitmapColor = texture2D(bitmapSampler, outBitmapTexCoords);\n";
247const char* gFS_Main_FetchBitmapNpot =
248        "    vec4 bitmapColor = texture2D(bitmapSampler, wrap(outBitmapTexCoords));\n";
249const char* gFS_Main_BlendShadersBG =
250        "    fragColor = blendShaders(gradientColor, bitmapColor)";
251const char* gFS_Main_BlendShadersGB =
252        "    fragColor = blendShaders(bitmapColor, gradientColor)";
253const char* gFS_Main_BlendShaders_Modulate[3] = {
254        // Don't modulate
255        ";\n",
256        // Modulate
257        " * fragColor.a;\n",
258        // Modulate with alpha 8 texture
259        " * texture2D(sampler, outTexCoords).a;\n"
260};
261const char* gFS_Main_GradientShader_Modulate[3] = {
262        // Don't modulate
263        "    fragColor = gradientColor;\n",
264        // Modulate
265        "    fragColor = gradientColor * fragColor.a;\n",
266        // Modulate with alpha 8 texture
267        "    fragColor = gradientColor * texture2D(sampler, outTexCoords).a;\n"
268    };
269const char* gFS_Main_BitmapShader_Modulate[3] = {
270        // Don't modulate
271        "    fragColor = bitmapColor;\n",
272        // Modulate
273        "    fragColor = bitmapColor * fragColor.a;\n",
274        // Modulate with alpha 8 texture
275        "    fragColor = bitmapColor * texture2D(sampler, outTexCoords).a;\n"
276    };
277const char* gFS_Main_FragColor =
278        "    gl_FragColor = fragColor;\n";
279const char* gFS_Main_FragColor_Blend =
280        "    gl_FragColor = blendFramebuffer(fragColor, gl_LastFragColor);\n";
281const char* gFS_Main_FragColor_Blend_Swap =
282        "    gl_FragColor = blendFramebuffer(gl_LastFragColor, fragColor);\n";
283const char* gFS_Main_ApplyColorOp[4] = {
284        // None
285        "",
286        // Matrix
287        // TODO: Fix premultiplied alpha computations for color matrix
288        "    fragColor *= colorMatrix;\n"
289        "    fragColor += colorMatrixVector;\n"
290        "    fragColor.rgb *= fragColor.a;\n",
291        // Lighting
292        "    float lightingAlpha = fragColor.a;\n"
293        "    fragColor = min(fragColor * lightingMul + (lightingAdd * lightingAlpha), lightingAlpha);\n"
294        "    fragColor.a = lightingAlpha;\n",
295        // PorterDuff
296        "    fragColor = blendColors(colorBlend, fragColor);\n"
297};
298const char* gFS_Footer =
299        "}\n\n";
300
301///////////////////////////////////////////////////////////////////////////////
302// PorterDuff snippets
303///////////////////////////////////////////////////////////////////////////////
304
305const char* gBlendOps[18] = {
306        // Clear
307        "return vec4(0.0, 0.0, 0.0, 0.0);\n",
308        // Src
309        "return src;\n",
310        // Dst
311        "return dst;\n",
312        // SrcOver
313        "return src + dst * (1.0 - src.a);\n",
314        // DstOver
315        "return dst + src * (1.0 - dst.a);\n",
316        // SrcIn
317        "return src * dst.a;\n",
318        // DstIn
319        "return dst * src.a;\n",
320        // SrcOut
321        "return src * (1.0 - dst.a);\n",
322        // DstOut
323        "return dst * (1.0 - src.a);\n",
324        // SrcAtop
325        "return vec4(src.rgb * dst.a + (1.0 - src.a) * dst.rgb, dst.a);\n",
326        // DstAtop
327        "return vec4(dst.rgb * src.a + (1.0 - dst.a) * src.rgb, src.a);\n",
328        // Xor
329        "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb, "
330                "src.a + dst.a - 2.0 * src.a * dst.a);\n",
331        // Add
332        "return min(src + dst, 1.0);\n",
333        // Multiply
334        "return src * dst;\n",
335        // Screen
336        "return src + dst - src * dst;\n",
337        // Overlay
338        "return clamp(vec4(mix("
339                "2.0 * src.rgb * dst.rgb + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), "
340                "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), "
341                "step(dst.a, 2.0 * dst.rgb)), "
342                "src.a + dst.a - src.a * dst.a), 0.0, 1.0);\n",
343        // Darken
344        "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + "
345                "min(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n",
346        // Lighten
347        "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + "
348                "max(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n",
349};
350
351///////////////////////////////////////////////////////////////////////////////
352// Constructors/destructors
353///////////////////////////////////////////////////////////////////////////////
354
355ProgramCache::ProgramCache() {
356}
357
358ProgramCache::~ProgramCache() {
359    clear();
360}
361
362///////////////////////////////////////////////////////////////////////////////
363// Cache management
364///////////////////////////////////////////////////////////////////////////////
365
366void ProgramCache::clear() {
367    PROGRAM_LOGD("Clearing program cache");
368
369    size_t count = mCache.size();
370    for (size_t i = 0; i < count; i++) {
371        delete mCache.valueAt(i);
372    }
373    mCache.clear();
374}
375
376Program* ProgramCache::get(const ProgramDescription& description) {
377    programid key = description.key();
378    ssize_t index = mCache.indexOfKey(key);
379    Program* program = NULL;
380    if (index < 0) {
381        description.log("Could not find program");
382        program = generateProgram(description, key);
383        mCache.add(key, program);
384    } else {
385        program = mCache.valueAt(index);
386    }
387    return program;
388}
389
390///////////////////////////////////////////////////////////////////////////////
391// Program generation
392///////////////////////////////////////////////////////////////////////////////
393
394Program* ProgramCache::generateProgram(const ProgramDescription& description, programid key) {
395    String8 vertexShader = generateVertexShader(description);
396    String8 fragmentShader = generateFragmentShader(description);
397
398    Program* program = new Program(description, vertexShader.string(), fragmentShader.string());
399    return program;
400}
401
402String8 ProgramCache::generateVertexShader(const ProgramDescription& description) {
403    // Add attributes
404    String8 shader(gVS_Header_Attributes);
405    if (description.hasTexture || description.hasExternalTexture) {
406        shader.append(gVS_Header_Attributes_TexCoords);
407    }
408    if (description.isAA) {
409        shader.append(gVS_Header_Attributes_AAParameters);
410    }
411    // Uniforms
412    shader.append(gVS_Header_Uniforms);
413    if (description.hasTextureTransform) {
414        shader.append(gVS_Header_Uniforms_TextureTransform);
415    }
416    if (description.hasGradient) {
417        shader.append(gVS_Header_Uniforms_HasGradient[description.gradientType]);
418    }
419    if (description.hasBitmap) {
420        shader.append(gVS_Header_Uniforms_HasBitmap);
421    }
422    if (description.isPoint) {
423        shader.append(gVS_Header_Uniforms_IsPoint);
424    }
425    // Varyings
426    if (description.hasTexture || description.hasExternalTexture) {
427        shader.append(gVS_Header_Varyings_HasTexture);
428    }
429    if (description.isAA) {
430        shader.append(gVS_Header_Varyings_IsAA);
431    }
432    if (description.hasGradient) {
433        shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]);
434    }
435    if (description.hasBitmap) {
436        shader.append(description.isPoint ?
437                gVS_Header_Varyings_PointHasBitmap :
438                gVS_Header_Varyings_HasBitmap);
439    }
440
441    // Begin the shader
442    shader.append(gVS_Main); {
443        if (description.hasTextureTransform) {
444            shader.append(gVS_Main_OutTransformedTexCoords);
445        } else if (description.hasTexture || description.hasExternalTexture) {
446            shader.append(gVS_Main_OutTexCoords);
447        }
448        if (description.isAA) {
449            shader.append(gVS_Main_AA);
450        }
451        if (description.hasGradient) {
452            shader.append(gVS_Main_OutGradient[description.gradientType]);
453        }
454        if (description.hasBitmap) {
455            shader.append(description.isPoint ?
456                    gVS_Main_OutPointBitmapTexCoords :
457                    gVS_Main_OutBitmapTexCoords);
458        }
459        if (description.isPoint) {
460            shader.append(gVS_Main_PointSize);
461        }
462        // Output transformed position
463        shader.append(gVS_Main_Position);
464    }
465    // End the shader
466    shader.append(gVS_Footer);
467
468    PROGRAM_LOGD("*** Generated vertex shader:\n\n%s", shader.string());
469
470    return shader;
471}
472
473String8 ProgramCache::generateFragmentShader(const ProgramDescription& description) {
474    String8 shader;
475
476    const bool blendFramebuffer = description.framebufferMode >= SkXfermode::kPlus_Mode;
477    if (blendFramebuffer) {
478        shader.append(gFS_Header_Extension_FramebufferFetch);
479    }
480    if (description.hasExternalTexture) {
481        shader.append(gFS_Header_Extension_ExternalTexture);
482    }
483
484    shader.append(gFS_Header);
485
486    // Varyings
487    if (description.hasTexture || description.hasExternalTexture) {
488        shader.append(gVS_Header_Varyings_HasTexture);
489    }
490    if (description.isAA) {
491        shader.append(gVS_Header_Varyings_IsAA);
492    }
493    if (description.hasGradient) {
494        shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]);
495    }
496    if (description.hasBitmap) {
497        shader.append(description.isPoint ?
498                gVS_Header_Varyings_PointHasBitmap :
499                gVS_Header_Varyings_HasBitmap);
500    }
501
502    // Uniforms
503    int modulateOp = MODULATE_OP_NO_MODULATE;
504    const bool singleColor = !description.hasTexture && !description.hasExternalTexture &&
505            !description.hasGradient && !description.hasBitmap;
506
507    if (description.modulate || singleColor) {
508        shader.append(gFS_Uniforms_Color);
509        if (!singleColor) modulateOp = MODULATE_OP_MODULATE;
510    }
511    if (description.hasTexture) {
512        shader.append(gFS_Uniforms_TextureSampler);
513    } else if (description.hasExternalTexture) {
514        shader.append(gFS_Uniforms_ExternalTextureSampler);
515    }
516    if (description.isAA) {
517        shader.append(gFS_Uniforms_AA);
518    }
519    if (description.hasGradient) {
520        shader.append(gFS_Uniforms_GradientSampler[description.gradientType]);
521    }
522    if (description.hasBitmap && description.isPoint) {
523        shader.append(gFS_Header_Uniforms_PointHasBitmap);
524    }
525    if (description.hasGammaCorrection) {
526        shader.append(gFS_Uniforms_Gamma);
527    }
528
529    // Optimization for common cases
530    if (!description.isAA && !blendFramebuffer &&
531            description.colorOp == ProgramDescription::kColorNone && !description.isPoint) {
532        bool fast = false;
533
534        const bool noShader = !description.hasGradient && !description.hasBitmap;
535        const bool singleTexture = (description.hasTexture || description.hasExternalTexture) &&
536                !description.hasAlpha8Texture && noShader;
537        const bool singleA8Texture = description.hasTexture &&
538                description.hasAlpha8Texture && noShader;
539        const bool singleGradient = !description.hasTexture && !description.hasExternalTexture &&
540                description.hasGradient && !description.hasBitmap &&
541                description.gradientType == ProgramDescription::kGradientLinear;
542
543        if (singleColor) {
544            shader.append(gFS_Fast_SingleColor);
545            fast = true;
546        } else if (singleTexture) {
547            if (!description.modulate) {
548                shader.append(gFS_Fast_SingleTexture);
549            } else {
550                shader.append(gFS_Fast_SingleModulateTexture);
551            }
552            fast = true;
553        } else if (singleA8Texture) {
554            if (!description.modulate) {
555                if (description.hasGammaCorrection) {
556                    shader.append(gFS_Fast_SingleA8Texture_ApplyGamma);
557                } else {
558                    shader.append(gFS_Fast_SingleA8Texture);
559                }
560            } else {
561                if (description.hasGammaCorrection) {
562                    shader.append(gFS_Fast_SingleModulateA8Texture_ApplyGamma);
563                } else {
564                    shader.append(gFS_Fast_SingleModulateA8Texture);
565                }
566            }
567            fast = true;
568        } else if (singleGradient) {
569            if (!description.modulate) {
570                shader.append(gFS_Fast_SingleGradient);
571            } else {
572                shader.append(gFS_Fast_SingleModulateGradient);
573            }
574            fast = true;
575        }
576
577        if (fast) {
578#if DEBUG_PROGRAMS
579                PROGRAM_LOGD("*** Fast case:\n");
580                PROGRAM_LOGD("*** Generated fragment shader:\n\n");
581                printLongString(shader);
582#endif
583
584            return shader;
585        }
586    }
587
588    if (description.hasBitmap) {
589        shader.append(gFS_Uniforms_BitmapSampler);
590    }
591    shader.append(gFS_Uniforms_ColorOp[description.colorOp]);
592
593    // Generate required functions
594    if (description.hasGradient && description.hasBitmap) {
595        generateBlend(shader, "blendShaders", description.shadersMode);
596    }
597    if (description.colorOp == ProgramDescription::kColorBlend) {
598        generateBlend(shader, "blendColors", description.colorMode);
599    }
600    if (blendFramebuffer) {
601        generateBlend(shader, "blendFramebuffer", description.framebufferMode);
602    }
603    if (description.isBitmapNpot) {
604        generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT);
605    }
606
607    // Begin the shader
608    shader.append(gFS_Main); {
609        // Stores the result in fragColor directly
610        if (description.hasTexture || description.hasExternalTexture) {
611            if (description.hasAlpha8Texture) {
612                if (!description.hasGradient && !description.hasBitmap) {
613                    shader.append(gFS_Main_FetchA8Texture[modulateOp]);
614                }
615            } else {
616                shader.append(gFS_Main_FetchTexture[modulateOp]);
617            }
618        } else {
619            if ((!description.hasGradient && !description.hasBitmap) || description.modulate) {
620                shader.append(gFS_Main_FetchColor);
621            }
622        }
623        if (description.isAA) {
624            shader.append(gFS_Main_AccountForAA);
625        }
626        if (description.hasGradient) {
627            shader.append(gFS_Main_FetchGradient[description.gradientType]);
628        }
629        if (description.hasBitmap) {
630            if (description.isPoint) {
631                shader.append(gFS_Main_PointBitmapTexCoords);
632            }
633            if (!description.isBitmapNpot) {
634                shader.append(gFS_Main_FetchBitmap);
635            } else {
636                shader.append(gFS_Main_FetchBitmapNpot);
637            }
638        }
639        bool applyModulate = false;
640        // Case when we have two shaders set
641        if (description.hasGradient && description.hasBitmap) {
642            int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp;
643            if (description.isBitmapFirst) {
644                shader.append(gFS_Main_BlendShadersBG);
645            } else {
646                shader.append(gFS_Main_BlendShadersGB);
647            }
648            shader.append(gFS_Main_BlendShaders_Modulate[op]);
649            applyModulate = true;
650        } else {
651            if (description.hasGradient) {
652                int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp;
653                shader.append(gFS_Main_GradientShader_Modulate[op]);
654                applyModulate = true;
655            } else if (description.hasBitmap) {
656                int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp;
657                shader.append(gFS_Main_BitmapShader_Modulate[op]);
658                applyModulate = true;
659            }
660        }
661        if (description.modulate && applyModulate) {
662            if (description.hasGammaCorrection) {
663                shader.append(gFS_Main_ModulateColor_ApplyGamma);
664            } else {
665                shader.append(gFS_Main_ModulateColor);
666            }
667        }
668        // Apply the color op if needed
669        shader.append(gFS_Main_ApplyColorOp[description.colorOp]);
670        // Output the fragment
671        if (!blendFramebuffer) {
672            shader.append(gFS_Main_FragColor);
673        } else {
674            shader.append(!description.swapSrcDst ?
675                    gFS_Main_FragColor_Blend : gFS_Main_FragColor_Blend_Swap);
676        }
677    }
678    // End the shader
679    shader.append(gFS_Footer);
680
681#if DEBUG_PROGRAMS
682        PROGRAM_LOGD("*** Generated fragment shader:\n\n");
683        printLongString(shader);
684#endif
685
686    return shader;
687}
688
689void ProgramCache::generateBlend(String8& shader, const char* name, SkXfermode::Mode mode) {
690    shader.append("\nvec4 ");
691    shader.append(name);
692    shader.append("(vec4 src, vec4 dst) {\n");
693    shader.append("    ");
694    shader.append(gBlendOps[mode]);
695    shader.append("}\n");
696}
697
698void ProgramCache::generateTextureWrap(String8& shader, GLenum wrapS, GLenum wrapT) {
699    shader.append("\nhighp vec2 wrap(highp vec2 texCoords) {\n");
700    if (wrapS == GL_MIRRORED_REPEAT) {
701        shader.append("    highp float xMod2 = mod(texCoords.x, 2.0);\n");
702        shader.append("    if (xMod2 > 1.0) xMod2 = 2.0 - xMod2;\n");
703    }
704    if (wrapT == GL_MIRRORED_REPEAT) {
705        shader.append("    highp float yMod2 = mod(texCoords.y, 2.0);\n");
706        shader.append("    if (yMod2 > 1.0) yMod2 = 2.0 - yMod2;\n");
707    }
708    shader.append("    return vec2(");
709    switch (wrapS) {
710        case GL_CLAMP_TO_EDGE:
711            shader.append("texCoords.x");
712            break;
713        case GL_REPEAT:
714            shader.append("mod(texCoords.x, 1.0)");
715            break;
716        case GL_MIRRORED_REPEAT:
717            shader.append("xMod2");
718            break;
719    }
720    shader.append(", ");
721    switch (wrapT) {
722        case GL_CLAMP_TO_EDGE:
723            shader.append("texCoords.y");
724            break;
725        case GL_REPEAT:
726            shader.append("mod(texCoords.y, 1.0)");
727            break;
728        case GL_MIRRORED_REPEAT:
729            shader.append("yMod2");
730            break;
731    }
732    shader.append(");\n");
733    shader.append("}\n");
734}
735
736void ProgramCache::printLongString(const String8& shader) const {
737    ssize_t index = 0;
738    ssize_t lastIndex = 0;
739    const char* str = shader.string();
740    while ((index = shader.find("\n", index)) > -1) {
741        String8 line(str, index - lastIndex);
742        if (line.length() == 0) line.append("\n");
743        PROGRAM_LOGD("%s", line.string());
744        index++;
745        str += (index - lastIndex);
746        lastIndex = index;
747    }
748}
749
750}; // namespace uirenderer
751}; // namespace android
752