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