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