ProgramCache.cpp revision 06f96e2652e4855b6520ad9dd70583677605b79a
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// Vertex shaders snippets 28/////////////////////////////////////////////////////////////////////////////// 29 30// TODO: Implement BitmapShader, implement repeat/mirror for npot 31 32const char* gVS_Header_Attributes = 33 "attribute vec4 position;\n"; 34const char* gVS_Header_Attributes_TexCoords = 35 "attribute vec2 texCoords;\n"; 36const char* gVS_Header_Uniforms = 37 "uniform mat4 transform;\n"; 38const char* gVS_Header_Uniforms_HasGradient = 39 "uniform float gradientLength;\n" 40 "uniform vec2 gradient;\n" 41 "uniform vec2 gradientStart;\n" 42 "uniform mat4 screenSpace;\n"; 43const char* gVS_Header_Uniforms_HasBitmap = 44 "uniform mat4 textureTransform;\n" 45 "uniform vec2 textureDimension;\n"; 46const char* gVS_Header_Varyings_HasTexture = 47 "varying vec2 outTexCoords;\n"; 48const char* gVS_Header_Varyings_HasBitmap = 49 "varying vec2 outBitmapTexCoords;\n"; 50const char* gVS_Header_Varyings_HasGradient = 51 "varying float index;\n"; 52const char* gVS_Main = 53 "\nvoid main(void) {\n"; 54const char* gVS_Main_OutTexCoords = 55 " outTexCoords = texCoords;\n"; 56const char* gVS_Main_OutGradientIndex = 57 " vec4 location = screenSpace * position;\n" 58 " index = dot(location.xy - gradientStart, gradient) * gradientLength;\n"; 59const char* gVS_Main_OutBitmapTexCoords = 60 " vec4 bitmapCoords = textureTransform * position;\n" 61 " outBitmapTexCoords = bitmapCoords.xy * textureDimension;\n"; 62const char* gVS_Main_Position = 63 " gl_Position = transform * position;\n"; 64const char* gVS_Footer = 65 "}\n\n"; 66 67/////////////////////////////////////////////////////////////////////////////// 68// Fragment shaders snippets 69/////////////////////////////////////////////////////////////////////////////// 70 71const char* gFS_Header = 72 "precision mediump float;\n\n"; 73const char* gFS_Uniforms_Color = 74 "uniform vec4 color;\n"; 75const char* gFS_Uniforms_TextureSampler = 76 "uniform sampler2D sampler;\n"; 77const char* gFS_Uniforms_GradientSampler = 78 "uniform sampler2D gradientSampler;\n"; 79const char* gFS_Uniforms_BitmapSampler = 80 "uniform sampler2D bitmapSampler;\n"; 81const char* gFS_Uniforms_ColorOp[4] = { 82 // None 83 "", 84 // Matrix 85 "uniform mat4 colorMatrix;\n" 86 "uniform vec4 colorMatrixVector;\n", 87 // Lighting 88 "uniform float lightingMul;\n" 89 "uniform float lightingAdd;\n", 90 // PorterDuff 91 "uniform vec4 colorBLend;\n" 92}; 93const char* gFS_Main = 94 "\nvoid main(void) {\n" 95 " vec4 fragColor;\n"; 96const char* gFS_Main_FetchColor = 97 " fragColor = color;\n"; 98const char* gFS_Main_FetchTexture = 99 " fragColor = color * texture2D(sampler, outTexCoords);\n"; 100const char* gFS_Main_FetchA8Texture = 101 " fragColor = color * texture2D(sampler, outTexCoords).a;\n"; 102const char* gFS_Main_FetchGradient = 103 " vec4 gradientColor = texture2D(gradientSampler, vec2(index, 0.5));\n"; 104const char* gFS_Main_FetchBitmap = 105 " vec4 bitmapColor = texture2D(bitmapSampler, outBitmapTexCoords);\n"; 106const char* gFS_Main_FetchBitmapNpot = 107 " vec4 bitmapColor = texture2D(bitmapSampler, wrap(outBitmapTexCoords));\n"; 108const char* gFS_Main_BlendShadersBG = 109 " fragColor = blendShaders(gradientColor, bitmapColor)"; 110const char* gFS_Main_BlendShadersGB = 111 " fragColor = blendShaders(bitmapColor, gradientColor)"; 112const char* gFS_Main_BlendShaders_Modulate = 113 " * fragColor.a;\n"; 114const char* gFS_Main_GradientShader_Modulate = 115 " fragColor = gradientColor * fragColor.a;\n"; 116const char* gFS_Main_BitmapShader_Modulate = 117 " fragColor = bitmapColor * fragColor.a;\n"; 118const char* gFS_Main_FragColor = 119 " gl_FragColor = fragColor;\n"; 120const char* gFS_Main_ApplyColorOp[4] = { 121 // None 122 "", 123 // Matrix 124 " fragColor *= colorMatrix;\n" 125 " fragColor += colorMatrixVector;\n", 126 // Lighting 127 " fragColor *= lightingMul;\n" 128 " fragColor += lightingAdd;\n", 129 // PorterDuff 130 " fragColor = blendColors(colorBlend, fragColor);\n" 131}; 132const char* gFS_Footer = 133 "}\n\n"; 134 135/////////////////////////////////////////////////////////////////////////////// 136// PorterDuff snippets 137/////////////////////////////////////////////////////////////////////////////// 138 139const char* gPorterDuff[12] = { 140 // Clear 141 "return vec4(0.0, 0.0, 0.0, 0.0);\n", 142 // Src 143 "return src;\n", 144 // Dst 145 "return dst;\n", 146 // SrcOver 147 "return src + dst * (1.0 - src.a);\n", 148 // DstOver 149 "return dst + src * (1.0 - dst.a);\n", 150 // SrcIn 151 "return src * dst.a;\n", 152 // DstIn 153 "return dst * src.a;\n", 154 // SrcOut 155 "return src * (1.0 - dst.a);\n", 156 // DstOut 157 "return dst * (1.0 - src.a);\n", 158 // SrcAtop 159 "return vec4(src.rgb * dst.a + (1.0 - src.a) * dst.rgb, dst.a);\n", 160 // DstAtop 161 "return vec4(dst.rgb * src.a + (1.0 - dst.a) * src.rgb, src.a);\n", 162 // Xor 163 "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb, 1.0, " 164 "src.a + dst.a - 2.0 * src.a * dst.a);\n", 165}; 166 167/////////////////////////////////////////////////////////////////////////////// 168// Constructors/destructors 169/////////////////////////////////////////////////////////////////////////////// 170 171ProgramCache::ProgramCache() { 172} 173 174ProgramCache::~ProgramCache() { 175 clear(); 176} 177 178/////////////////////////////////////////////////////////////////////////////// 179// Cache management 180/////////////////////////////////////////////////////////////////////////////// 181 182void ProgramCache::clear() { 183 size_t count = mCache.size(); 184 for (size_t i = 0; i < count; i++) { 185 delete mCache.valueAt(i); 186 } 187 mCache.clear(); 188} 189 190Program* ProgramCache::get(const ProgramDescription& description) { 191 programid key = description.key(); 192 ssize_t index = mCache.indexOfKey(key); 193 Program* program = NULL; 194 if (index < 0) { 195 PROGRAM_LOGD("Could not find program with key 0x%x", key); 196 program = generateProgram(description, key); 197 mCache.add(key, program); 198 } else { 199 program = mCache.valueAt(index); 200 } 201 return program; 202} 203 204/////////////////////////////////////////////////////////////////////////////// 205// Program generation 206/////////////////////////////////////////////////////////////////////////////// 207 208Program* ProgramCache::generateProgram(const ProgramDescription& description, programid key) { 209 String8 vertexShader = generateVertexShader(description); 210 String8 fragmentShader = generateFragmentShader(description); 211 212 Program* program = new Program(vertexShader.string(), fragmentShader.string()); 213 return program; 214} 215 216String8 ProgramCache::generateVertexShader(const ProgramDescription& description) { 217 // Add attributes 218 String8 shader(gVS_Header_Attributes); 219 if (description.hasTexture) { 220 shader.append(gVS_Header_Attributes_TexCoords); 221 } 222 // Uniforms 223 shader.append(gVS_Header_Uniforms); 224 if (description.hasGradient) { 225 shader.append(gVS_Header_Uniforms_HasGradient); 226 } 227 if (description.hasBitmap) { 228 shader.append(gVS_Header_Uniforms_HasBitmap); 229 } 230 // Varyings 231 if (description.hasTexture) { 232 shader.append(gVS_Header_Varyings_HasTexture); 233 } 234 if (description.hasGradient) { 235 shader.append(gVS_Header_Varyings_HasGradient); 236 } 237 if (description.hasBitmap) { 238 shader.append(gVS_Header_Varyings_HasBitmap); 239 } 240 241 // Begin the shader 242 shader.append(gVS_Main); { 243 if (description.hasTexture) { 244 shader.append(gVS_Main_OutTexCoords); 245 } 246 if (description.hasGradient) { 247 shader.append(gVS_Main_OutGradientIndex); 248 } 249 if (description.hasBitmap) { 250 shader.append(gVS_Main_OutBitmapTexCoords); 251 } 252 // Output transformed position 253 shader.append(gVS_Main_Position); 254 } 255 // End the shader 256 shader.append(gVS_Footer); 257 258 PROGRAM_LOGD("*** Generated vertex shader:\n\n%s", shader.string()); 259 260 return shader; 261} 262 263String8 ProgramCache::generateFragmentShader(const ProgramDescription& description) { 264 // Set the default precision 265 String8 shader(gFS_Header); 266 267 // Varyings 268 if (description.hasTexture) { 269 shader.append(gVS_Header_Varyings_HasTexture); 270 } 271 if (description.hasGradient) { 272 shader.append(gVS_Header_Varyings_HasGradient); 273 } 274 if (description.hasBitmap) { 275 shader.append(gVS_Header_Varyings_HasBitmap); 276 } 277 278 279 // Uniforms 280 shader.append(gFS_Uniforms_Color); 281 if (description.hasTexture) { 282 shader.append(gFS_Uniforms_TextureSampler); 283 } 284 if (description.hasGradient) { 285 shader.append(gFS_Uniforms_GradientSampler); 286 } 287 if (description.hasBitmap) { 288 shader.append(gFS_Uniforms_BitmapSampler); 289 } 290 shader.append(gFS_Uniforms_ColorOp[description.colorOp]); 291 292 // Generate required functions 293 if (description.hasGradient && description.hasBitmap) { 294 generatePorterDuffBlend(shader, "blendShaders", description.shadersMode); 295 } 296 if (description.colorOp == ProgramDescription::kColorBlend) { 297 generatePorterDuffBlend(shader, "blendColors", description.colorMode); 298 } 299 if (description.isBitmapNpot) { 300 generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT); 301 } 302 303 // Begin the shader 304 shader.append(gFS_Main); { 305 // Stores the result in fragColor directly 306 if (description.hasTexture) { 307 if (description.hasAlpha8Texture) { 308 shader.append(gFS_Main_FetchA8Texture); 309 } else { 310 shader.append(gFS_Main_FetchTexture); 311 } 312 } else { 313 shader.append(gFS_Main_FetchColor); 314 } 315 if (description.hasGradient) { 316 shader.append(gFS_Main_FetchGradient); 317 } 318 if (description.hasBitmap) { 319 if (!description.isBitmapNpot) { 320 shader.append(gFS_Main_FetchBitmap); 321 } else { 322 shader.append(gFS_Main_FetchBitmapNpot); 323 } 324 } 325 // Case when we have two shaders set 326 if (description.hasGradient && description.hasBitmap) { 327 if (description.isBitmapFirst) { 328 shader.append(gFS_Main_BlendShadersBG); 329 } else { 330 shader.append(gFS_Main_BlendShadersGB); 331 } 332 shader.append(gFS_Main_BlendShaders_Modulate); 333 } else { 334 if (description.hasGradient) { 335 shader.append(gFS_Main_GradientShader_Modulate); 336 } else if (description.hasBitmap) { 337 shader.append(gFS_Main_BitmapShader_Modulate); 338 } 339 } 340 // Apply the color op if needed 341 shader.append(gFS_Main_ApplyColorOp[description.colorOp]); 342 // Output the fragment 343 shader.append(gFS_Main_FragColor); 344 } 345 // End the shader 346 shader.append(gFS_Footer); 347 348 PROGRAM_LOGD("*** Generated fragment shader:\n\n%s", shader.string()); 349 return shader; 350} 351 352void ProgramCache::generatePorterDuffBlend(String8& shader, const char* name, 353 SkXfermode::Mode mode) { 354 shader.append("\nvec4 "); 355 shader.append(name); 356 shader.append("(vec4 src, vec4 dst) {\n"); 357 shader.append(" "); 358 shader.append(gPorterDuff[mode]); 359 shader.append("}\n"); 360} 361 362void ProgramCache::generateTextureWrap(String8& shader, GLenum wrapS, GLenum wrapT) { 363 shader.append("\nvec2 wrap(vec2 texCoords) {\n"); 364 if (wrapS == GL_MIRRORED_REPEAT) { 365 shader.append(" float xMod2 = mod(texCoords.x, 2.0);\n"); 366 shader.append(" if (xMod2 > 1.0) xMod2 = 2.0 - xMod2;\n"); 367 } 368 if (wrapT == GL_MIRRORED_REPEAT) { 369 shader.append(" float yMod2 = mod(texCoords.y, 2.0);\n"); 370 shader.append(" if (yMod2 > 1.0) yMod2 = 2.0 - yMod2;\n"); 371 } 372 shader.append(" return vec2("); 373 switch (wrapS) { 374 case GL_REPEAT: 375 shader.append("mod(texCoords.x, 1.0)"); 376 break; 377 case GL_MIRRORED_REPEAT: 378 shader.append("xMod2"); 379 break; 380 } 381 shader.append(", "); 382 switch (wrapT) { 383 case GL_REPEAT: 384 shader.append("mod(texCoords.y, 1.0)"); 385 break; 386 case GL_MIRRORED_REPEAT: 387 shader.append("yMod2"); 388 break; 389 } 390 shader.append(");\n"); 391 shader.append("}\n"); 392} 393 394}; // namespace uirenderer 395}; // namespace android 396