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