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