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