void ProgramCache::clear() { PROGRAM_LOGD("Clearing program cache"); size_t count = mCache.size(); for (size_t i = 0; i < count; i++) { delete mCache.valueAt(i); } mCache.clear(); }
void ProgramCache::printLongString(const String8& shader) const { ssize_t index = 0; ssize_t lastIndex = 0; const char* str = shader.string(); while ((index = shader.find("\n", index)) > -1) { String8 line(str, index - lastIndex); if (line.length() == 0) line.append("\n"); PROGRAM_LOGD("%s", line.string()); index++; str += (index - lastIndex); lastIndex = index; } }
String8 ProgramCache::generateFragmentShader(const ProgramDescription& description) { String8 shader; const bool blendFramebuffer = description.framebufferMode >= SkXfermode::kPlus_Mode; if (blendFramebuffer) { shader.append(gFS_Header_Extension_FramebufferFetch); } if (description.hasExternalTexture) { shader.append(gFS_Header_Extension_ExternalTexture); } shader.append(gFS_Header); // Varyings if (description.hasTexture || description.hasExternalTexture) { shader.append(gVS_Header_Varyings_HasTexture); } if (description.hasVertexAlpha) { shader.append(gVS_Header_Varyings_HasVertexAlpha); } if (description.hasColors) { shader.append(gVS_Header_Varyings_HasColors); } if (description.hasGradient) { shader.append(gVS_Header_Varyings_HasGradient[gradientIndex(description)]); } if (description.hasBitmap) { shader.append(gVS_Header_Varyings_HasBitmap); } if (description.hasRoundRectClip) { shader.append(gVS_Header_Varyings_HasRoundRectClip); } // Uniforms int modulateOp = MODULATE_OP_NO_MODULATE; const bool singleColor = !description.hasTexture && !description.hasExternalTexture && !description.hasGradient && !description.hasBitmap; if (description.modulate || singleColor) { shader.append(gFS_Uniforms_Color); if (!singleColor) modulateOp = MODULATE_OP_MODULATE; } if (description.hasTexture) { shader.append(gFS_Uniforms_TextureSampler); } else if (description.hasExternalTexture) { shader.append(gFS_Uniforms_ExternalTextureSampler); } if (description.hasGradient) { shader.appendFormat(gFS_Uniforms_GradientSampler[description.isSimpleGradient], gFS_Uniforms_Dither); } if (description.hasGammaCorrection) { shader.append(gFS_Uniforms_Gamma); } if (description.hasRoundRectClip) { shader.append(gFS_Uniforms_HasRoundRectClip); } // Optimization for common cases if (!description.hasVertexAlpha && !blendFramebuffer && !description.hasColors && description.colorOp == ProgramDescription::kColorNone && !description.hasDebugHighlight && !description.emulateStencil && !description.hasRoundRectClip) { bool fast = false; const bool noShader = !description.hasGradient && !description.hasBitmap; const bool singleTexture = (description.hasTexture || description.hasExternalTexture) && !description.hasAlpha8Texture && noShader; const bool singleA8Texture = description.hasTexture && description.hasAlpha8Texture && noShader; const bool singleGradient = !description.hasTexture && !description.hasExternalTexture && description.hasGradient && !description.hasBitmap && description.gradientType == ProgramDescription::kGradientLinear; if (singleColor) { shader.append(gFS_Fast_SingleColor); fast = true; } else if (singleTexture) { if (!description.modulate) { shader.append(gFS_Fast_SingleTexture); } else { shader.append(gFS_Fast_SingleModulateTexture); } fast = true; } else if (singleA8Texture) { if (!description.modulate) { if (description.hasGammaCorrection) { shader.append(gFS_Fast_SingleA8Texture_ApplyGamma); } else { shader.append(gFS_Fast_SingleA8Texture); } } else { if (description.hasGammaCorrection) { shader.append(gFS_Fast_SingleModulateA8Texture_ApplyGamma); } else { shader.append(gFS_Fast_SingleModulateA8Texture); } } fast = true; } else if (singleGradient) { if (!description.modulate) { shader.appendFormat(gFS_Fast_SingleGradient[description.isSimpleGradient], gFS_Main_Dither[mHasES3]); } else { shader.appendFormat(gFS_Fast_SingleModulateGradient[description.isSimpleGradient], gFS_Main_Dither[mHasES3]); } fast = true; } if (fast) { #if DEBUG_PROGRAMS PROGRAM_LOGD("*** Fast case:\n"); PROGRAM_LOGD("*** Generated fragment shader:\n\n"); printLongString(shader); #endif return shader; } } if (description.hasBitmap) { shader.append(gFS_Uniforms_BitmapSampler); } shader.append(gFS_Uniforms_ColorOp[description.colorOp]); // Generate required functions if (description.hasGradient && description.hasBitmap) { generateBlend(shader, "blendShaders", description.shadersMode); } if (description.colorOp == ProgramDescription::kColorBlend) { generateBlend(shader, "blendColors", description.colorMode); } if (blendFramebuffer) { generateBlend(shader, "blendFramebuffer", description.framebufferMode); } if (description.isBitmapNpot) { generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT); } // Begin the shader shader.append(gFS_Main); { if (description.emulateStencil) { shader.append(gFS_Main_EmulateStencil); } // Stores the result in fragColor directly if (description.hasTexture || description.hasExternalTexture) { if (description.hasAlpha8Texture) { if (!description.hasGradient && !description.hasBitmap) { shader.append(gFS_Main_FetchA8Texture[modulateOp * 2 + description.hasGammaCorrection]); } } else { shader.append(gFS_Main_FetchTexture[modulateOp]); } } else { if (!description.hasGradient && !description.hasBitmap) { shader.append(gFS_Main_FetchColor); } } if (description.hasGradient) { shader.append(gFS_Main_FetchGradient[gradientIndex(description)]); shader.appendFormat(gFS_Main_AddDitherToGradient, gFS_Main_Dither[mHasES3]); } if (description.hasBitmap) { if (!description.isBitmapNpot) { shader.append(gFS_Main_FetchBitmap); } else { shader.append(gFS_Main_FetchBitmapNpot); } } bool applyModulate = false; // Case when we have two shaders set if (description.hasGradient && description.hasBitmap) { if (description.isBitmapFirst) { shader.append(gFS_Main_BlendShadersBG); } else { shader.append(gFS_Main_BlendShadersGB); } applyModulate = shaderOp(description, shader, modulateOp, gFS_Main_BlendShaders_Modulate); } else { if (description.hasGradient) { applyModulate = shaderOp(description, shader, modulateOp, gFS_Main_GradientShader_Modulate); } else if (description.hasBitmap) { applyModulate = shaderOp(description, shader, modulateOp, gFS_Main_BitmapShader_Modulate); } } if (description.modulate && applyModulate) { shader.append(gFS_Main_ModulateColor); } // Apply the color op if needed shader.append(gFS_Main_ApplyColorOp[description.colorOp]); if (description.hasVertexAlpha) { if (description.useShadowAlphaInterp) { shader.append(gFS_Main_ApplyVertexAlphaShadowInterp); } else { shader.append(gFS_Main_ApplyVertexAlphaLinearInterp); } } // Output the fragment if (!blendFramebuffer) { shader.append(gFS_Main_FragColor); } else { shader.append(!description.swapSrcDst ? gFS_Main_FragColor_Blend : gFS_Main_FragColor_Blend_Swap); } if (description.hasColors) { shader.append(gFS_Main_FragColor_HasColors); } if (description.hasRoundRectClip) { shader.append(gFS_Main_FragColor_HasRoundRectClip); } if (description.hasDebugHighlight) { shader.append(gFS_Main_DebugHighlight); } } if (description.emulateStencil) { shader.append(gFS_Footer_EmulateStencil); } // End the shader shader.append(gFS_Footer); #if DEBUG_PROGRAMS PROGRAM_LOGD("*** Generated fragment shader:\n\n"); printLongString(shader); #endif return shader; }
String8 ProgramCache::generateVertexShader(const ProgramDescription& description) { // Add attributes String8 shader(gVS_Header_Attributes); if (description.hasTexture || description.hasExternalTexture) { shader.append(gVS_Header_Attributes_TexCoords); } if (description.hasVertexAlpha) { shader.append(gVS_Header_Attributes_VertexAlphaParameters); } if (description.hasColors) { shader.append(gVS_Header_Attributes_Colors); } // Uniforms shader.append(gVS_Header_Uniforms); if (description.hasTextureTransform) { shader.append(gVS_Header_Uniforms_TextureTransform); } if (description.hasGradient) { shader.append(gVS_Header_Uniforms_HasGradient); } if (description.hasBitmap) { shader.append(gVS_Header_Uniforms_HasBitmap); } if (description.hasRoundRectClip) { shader.append(gVS_Header_Uniforms_HasRoundRectClip); } // Varyings if (description.hasTexture || description.hasExternalTexture) { shader.append(gVS_Header_Varyings_HasTexture); } if (description.hasVertexAlpha) { shader.append(gVS_Header_Varyings_HasVertexAlpha); } if (description.hasColors) { shader.append(gVS_Header_Varyings_HasColors); } if (description.hasGradient) { shader.append(gVS_Header_Varyings_HasGradient[gradientIndex(description)]); } if (description.hasBitmap) { shader.append(gVS_Header_Varyings_HasBitmap); } if (description.hasRoundRectClip) { shader.append(gVS_Header_Varyings_HasRoundRectClip); } // Begin the shader shader.append(gVS_Main); { if (description.hasTextureTransform) { shader.append(gVS_Main_OutTransformedTexCoords); } else if (description.hasTexture || description.hasExternalTexture) { shader.append(gVS_Main_OutTexCoords); } if (description.hasVertexAlpha) { shader.append(gVS_Main_VertexAlpha); } if (description.hasColors) { shader.append(gVS_Main_OutColors); } if (description.hasBitmap) { shader.append(gVS_Main_OutBitmapTexCoords); } // Output transformed position shader.append(gVS_Main_Position); if (description.hasGradient) { shader.append(gVS_Main_OutGradient[gradientIndex(description)]); } if (description.hasRoundRectClip) { shader.append(gVS_Main_HasRoundRectClip); } } // End the shader shader.append(gVS_Footer); PROGRAM_LOGD("*** Generated vertex shader:\n\n%s", shader.string()); return shader; }
String8 ProgramCache::generateFragmentShader(const ProgramDescription& description) { String8 shader; const bool blendFramebuffer = description.framebufferMode >= SkXfermode::kPlus_Mode; if (blendFramebuffer) { shader.append(gFS_Header_Extension_FramebufferFetch); } if (description.hasExternalTexture) { shader.append(gFS_Header_Extension_ExternalTexture); } shader.append(gFS_Header); // Varyings if (description.hasTexture || description.hasExternalTexture) { shader.append(gVS_Header_Varyings_HasTexture); } if (description.isAA) { shader.append(gVS_Header_Varyings_IsAA); } if (description.hasGradient) { shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]); } if (description.hasBitmap) { int index = Caches::getInstance().extensions.needsHighpTexCoords() ? 1 : 0; shader.append(description.isPoint ? gVS_Header_Varyings_PointHasBitmap[index] : gVS_Header_Varyings_HasBitmap[index]); } // Uniforms int modulateOp = MODULATE_OP_NO_MODULATE; const bool singleColor = !description.hasTexture && !description.hasExternalTexture && !description.hasGradient && !description.hasBitmap; if (description.modulate || singleColor) { shader.append(gFS_Uniforms_Color); if (!singleColor) modulateOp = MODULATE_OP_MODULATE; } if (description.hasTexture) { shader.append(gFS_Uniforms_TextureSampler); } else if (description.hasExternalTexture) { shader.append(gFS_Uniforms_ExternalTextureSampler); } if (description.isAA) { shader.append(gFS_Uniforms_AA); } if (description.hasGradient) { shader.append(gFS_Uniforms_GradientSampler[description.gradientType]); } if (description.hasBitmap && description.isPoint) { shader.append(gFS_Header_Uniforms_PointHasBitmap); } // Optimization for common cases if (!description.isAA && !blendFramebuffer && description.colorOp == ProgramDescription::kColorNone && !description.isPoint) { bool fast = false; const bool noShader = !description.hasGradient && !description.hasBitmap; const bool singleTexture = (description.hasTexture || description.hasExternalTexture) && !description.hasAlpha8Texture && noShader; const bool singleA8Texture = description.hasTexture && description.hasAlpha8Texture && noShader; const bool singleGradient = !description.hasTexture && !description.hasExternalTexture && description.hasGradient && !description.hasBitmap && description.gradientType == ProgramDescription::kGradientLinear; if (singleColor) { shader.append(gFS_Fast_SingleColor); fast = true; } else if (singleTexture) { if (!description.modulate) { shader.append(gFS_Fast_SingleTexture); } else { shader.append(gFS_Fast_SingleModulateTexture); } fast = true; } else if (singleA8Texture) { if (!description.modulate) { shader.append(gFS_Fast_SingleA8Texture); } else { shader.append(gFS_Fast_SingleModulateA8Texture); } fast = true; } else if (singleGradient) { if (!description.modulate) { shader.append(gFS_Fast_SingleGradient); } else { shader.append(gFS_Fast_SingleModulateGradient); } fast = true; } if (fast) { #if DEBUG_PROGRAMS PROGRAM_LOGD("*** Fast case:\n"); PROGRAM_LOGD("*** Generated fragment shader:\n\n"); printLongString(shader); #endif return shader; } } if (description.hasBitmap) { shader.append(gFS_Uniforms_BitmapSampler); } shader.append(gFS_Uniforms_ColorOp[description.colorOp]); // Generate required functions if (description.hasGradient && description.hasBitmap) { generateBlend(shader, "blendShaders", description.shadersMode); } if (description.colorOp == ProgramDescription::kColorBlend) { generateBlend(shader, "blendColors", description.colorMode); } if (blendFramebuffer) { generateBlend(shader, "blendFramebuffer", description.framebufferMode); } if (description.isBitmapNpot) { generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT); } // Begin the shader shader.append(gFS_Main); { // Stores the result in fragColor directly if (description.hasTexture || description.hasExternalTexture) { if (description.hasAlpha8Texture) { if (!description.hasGradient && !description.hasBitmap) { shader.append(gFS_Main_FetchA8Texture[modulateOp]); } } else { shader.append(gFS_Main_FetchTexture[modulateOp]); } } else { if ((!description.hasGradient && !description.hasBitmap) || description.modulate) { shader.append(gFS_Main_FetchColor); } } if (description.isAA) { shader.append(gFS_Main_AccountForAA); } if (description.hasGradient) { shader.append(gFS_Main_FetchGradient[description.gradientType]); } if (description.hasBitmap) { if (description.isPoint) { shader.append(gFS_Main_PointBitmapTexCoords); } if (!description.isBitmapNpot) { shader.append(gFS_Main_FetchBitmap); } else { shader.append(gFS_Main_FetchBitmapNpot); } } bool applyModulate = false; // Case when we have two shaders set if (description.hasGradient && description.hasBitmap) { int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp; if (description.isBitmapFirst) { shader.append(gFS_Main_BlendShadersBG); } else { shader.append(gFS_Main_BlendShadersGB); } shader.append(gFS_Main_BlendShaders_Modulate[op]); applyModulate = true; } else { if (description.hasGradient) { int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp; shader.append(gFS_Main_GradientShader_Modulate[op]); applyModulate = true; } else if (description.hasBitmap) { int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp; shader.append(gFS_Main_BitmapShader_Modulate[op]); applyModulate = true; } } if (description.modulate && applyModulate) { shader.append(gFS_Main_ModulateColor); } // Apply the color op if needed shader.append(gFS_Main_ApplyColorOp[description.colorOp]); // Output the fragment if (!blendFramebuffer) { shader.append(gFS_Main_FragColor); } else { shader.append(!description.swapSrcDst ? gFS_Main_FragColor_Blend : gFS_Main_FragColor_Blend_Swap); } } // End the shader shader.append(gFS_Footer); #if DEBUG_PROGRAMS PROGRAM_LOGD("*** Generated fragment shader:\n\n"); printLongString(shader); #endif return shader; }
String8 ProgramCache::generateVertexShader(const ProgramDescription& description) { // Add attributes String8 shader(gVS_Header_Attributes); if (description.hasTexture || description.hasExternalTexture) { shader.append(gVS_Header_Attributes_TexCoords); } if (description.isAA) { shader.append(gVS_Header_Attributes_AAParameters); } // Uniforms shader.append(gVS_Header_Uniforms); if (description.hasTextureTransform) { shader.append(gVS_Header_Uniforms_TextureTransform); } if (description.hasGradient) { shader.append(gVS_Header_Uniforms_HasGradient[description.gradientType]); } if (description.hasBitmap) { shader.append(gVS_Header_Uniforms_HasBitmap); } if (description.isPoint) { shader.append(gVS_Header_Uniforms_IsPoint); } // Varyings if (description.hasTexture || description.hasExternalTexture) { shader.append(gVS_Header_Varyings_HasTexture); } if (description.isAA) { shader.append(gVS_Header_Varyings_IsAA); } if (description.hasGradient) { shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]); } if (description.hasBitmap) { int index = Caches::getInstance().extensions.needsHighpTexCoords() ? 1 : 0; shader.append(description.isPoint ? gVS_Header_Varyings_PointHasBitmap[index] : gVS_Header_Varyings_HasBitmap[index]); } // Begin the shader shader.append(gVS_Main); { if (description.hasTextureTransform) { shader.append(gVS_Main_OutTransformedTexCoords); } else if (description.hasTexture || description.hasExternalTexture) { shader.append(gVS_Main_OutTexCoords); } if (description.isAA) { shader.append(gVS_Main_AA); } if (description.hasGradient) { shader.append(gVS_Main_OutGradient[description.gradientType]); } if (description.hasBitmap) { shader.append(description.isPoint ? gVS_Main_OutPointBitmapTexCoords : gVS_Main_OutBitmapTexCoords); } if (description.isPoint) { shader.append(gVS_Main_PointSize); } // Output transformed position shader.append(gVS_Main_Position); } // End the shader shader.append(gVS_Footer); PROGRAM_LOGD("*** Generated vertex shader:\n\n%s", shader.string()); return shader; }