ProgramCache.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. /*
  2. * Copyright 2013 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. //#define LOG_NDEBUG 0
  17. #include <GLES2/gl2.h>
  18. #include <GLES2/gl2ext.h>
  19. #include <utils/String8.h>
  20. #include "ProgramCache.h"
  21. #include "Program.h"
  22. #include "Description.h"
  23. namespace android {
  24. // -----------------------------------------------------------------------------------------------
  25. /*
  26. * A simple formatter class to automatically add the endl and
  27. * manage the indentation.
  28. */
  29. class Formatter;
  30. static Formatter& indent(Formatter& f);
  31. static Formatter& dedent(Formatter& f);
  32. class Formatter {
  33. String8 mString;
  34. int mIndent;
  35. typedef Formatter& (*FormaterManipFunc)(Formatter&);
  36. friend Formatter& indent(Formatter& f);
  37. friend Formatter& dedent(Formatter& f);
  38. public:
  39. Formatter() : mIndent(0) {}
  40. String8 getString() const {
  41. return mString;
  42. }
  43. friend Formatter& operator << (Formatter& out, const char* in) {
  44. for (int i=0 ; i<out.mIndent ; i++) {
  45. out.mString.append(" ");
  46. }
  47. out.mString.append(in);
  48. out.mString.append("\n");
  49. return out;
  50. }
  51. friend inline Formatter& operator << (Formatter& out, const String8& in) {
  52. return operator << (out, in.string());
  53. }
  54. friend inline Formatter& operator<<(Formatter& to, FormaterManipFunc func) {
  55. return (*func)(to);
  56. }
  57. };
  58. Formatter& indent(Formatter& f) {
  59. f.mIndent++;
  60. return f;
  61. }
  62. Formatter& dedent(Formatter& f) {
  63. f.mIndent--;
  64. return f;
  65. }
  66. // -----------------------------------------------------------------------------------------------
  67. ANDROID_SINGLETON_STATIC_INSTANCE(ProgramCache)
  68. ProgramCache::ProgramCache() {
  69. // Until surfaceflinger has a dependable blob cache on the filesystem,
  70. // generate shaders on initialization so as to avoid jank.
  71. primeCache();
  72. }
  73. ProgramCache::~ProgramCache() {
  74. }
  75. void ProgramCache::primeCache() {
  76. uint32_t shaderCount = 0;
  77. uint32_t keyMask = Key::BLEND_MASK | Key::OPACITY_MASK |
  78. Key::PLANE_ALPHA_MASK | Key::TEXTURE_MASK;
  79. // Prime the cache for all combinations of the above masks,
  80. // leaving off the experimental color matrix mask options.
  81. nsecs_t timeBefore = systemTime();
  82. for (uint32_t keyVal = 0; keyVal <= keyMask; keyVal++) {
  83. Key shaderKey;
  84. shaderKey.set(keyMask, keyVal);
  85. uint32_t tex = shaderKey.getTextureTarget();
  86. if (tex != Key::TEXTURE_OFF &&
  87. tex != Key::TEXTURE_EXT &&
  88. tex != Key::TEXTURE_2D) {
  89. continue;
  90. }
  91. Program* program = mCache.valueFor(shaderKey);
  92. if (program == NULL) {
  93. program = generateProgram(shaderKey);
  94. mCache.add(shaderKey, program);
  95. shaderCount++;
  96. }
  97. }
  98. // Keys that are actually used by blurring.
  99. // This is obtained by log msg from useProgram()
  100. uint32_t blurringKeys[] = {
  101. 0x01000015,
  102. 0x01000011,
  103. };
  104. for (size_t i=0; i<sizeof(blurringKeys)/sizeof(blurringKeys[0]); ++i) {
  105. Key shaderKey;
  106. shaderKey.set(blurringKeys[i], blurringKeys[i]);
  107. Program* program = mCache.valueFor(shaderKey);
  108. if (program == NULL) {
  109. program = generateProgram(shaderKey);
  110. mCache.add(shaderKey, program);
  111. shaderCount++;
  112. }
  113. }
  114. nsecs_t timeAfter = systemTime();
  115. float compileTimeMs = static_cast<float>(timeAfter - timeBefore) / 1.0E6;
  116. ALOGD("SF. shader cache generated - %u shaders in %f ms\n", shaderCount, compileTimeMs);
  117. }
  118. ProgramCache::Key ProgramCache::computeKey(const Description& description) {
  119. Key needs;
  120. needs.set(Key::TEXTURE_MASK,
  121. !description.mTextureEnabled ? Key::TEXTURE_OFF :
  122. description.mTexture.getTextureTarget() == GL_TEXTURE_EXTERNAL_OES ? Key::TEXTURE_EXT :
  123. description.mTexture.getTextureTarget() == GL_TEXTURE_2D ? Key::TEXTURE_2D :
  124. Key::TEXTURE_OFF)
  125. .set(Key::PLANE_ALPHA_MASK,
  126. (description.mPlaneAlpha < 1) ? Key::PLANE_ALPHA_LT_ONE : Key::PLANE_ALPHA_EQ_ONE)
  127. .set(Key::BLEND_MASK,
  128. description.mPremultipliedAlpha ? Key::BLEND_PREMULT : Key::BLEND_NORMAL)
  129. .set(Key::OPACITY_MASK,
  130. description.mOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT)
  131. .set(Key::COLOR_MATRIX_MASK,
  132. description.mColorMatrixEnabled ? Key::COLOR_MATRIX_ON : Key::COLOR_MATRIX_OFF)
  133. .set(Key::TEXTURE_MASKING_MASK,
  134. !description.mMaskTextureEnabled ? Key::TEXTURE_MASKING_OFF :
  135. description.mMaskTexture.getTextureTarget() == GL_TEXTURE_EXTERNAL_OES ? Key::TEXTURE_MASKING_EXT :
  136. description.mMaskTexture.getTextureTarget() == GL_TEXTURE_2D ? Key::TEXTURE_MASKING_2D :
  137. Key::TEXTURE_MASKING_OFF);
  138. return needs;
  139. }
  140. String8 ProgramCache::generateVertexShader(const Key& needs) {
  141. Formatter vs;
  142. if (needs.isTexturing()) {
  143. vs << "attribute vec4 texCoords;"
  144. << "varying vec2 outTexCoords;";
  145. }
  146. vs << "attribute vec4 position;"
  147. << "uniform mat4 projection;"
  148. << "uniform mat4 texture;"
  149. << "void main(void) {" << indent
  150. << "gl_Position = projection * position;";
  151. if (needs.isTexturing()) {
  152. vs << "outTexCoords = (texture * texCoords).st;";
  153. }
  154. vs << dedent << "}";
  155. return vs.getString();
  156. }
  157. String8 ProgramCache::generateFragmentShader(const Key& needs) {
  158. Formatter fs;
  159. if (needs.getTextureTarget() == Key::TEXTURE_EXT) {
  160. fs << "#extension GL_OES_EGL_image_external : require";
  161. }
  162. // default precision is required-ish in fragment shaders
  163. fs << "precision mediump float;";
  164. if (needs.getTextureTarget() == Key::TEXTURE_EXT) {
  165. fs << "uniform samplerExternalOES sampler;"
  166. << "varying vec2 outTexCoords;";
  167. } else if (needs.getTextureTarget() == Key::TEXTURE_2D) {
  168. fs << "uniform sampler2D sampler;"
  169. << "varying vec2 outTexCoords;";
  170. } else if (needs.getTextureTarget() == Key::TEXTURE_OFF) {
  171. fs << "uniform vec4 color;";
  172. }
  173. if (needs.getTextureMaskingTarget() == Key::TEXTURE_MASKING_EXT) {
  174. fs << "uniform samplerExternalOES samplerMask;";
  175. } else if (needs.getTextureMaskingTarget() == Key::TEXTURE_MASKING_2D) {
  176. fs << "uniform sampler2D samplerMask;";
  177. }
  178. if (needs.getTextureMaskingTarget() != Key::TEXTURE_MASKING_OFF) {
  179. fs << "uniform float maskAlphaThreshold;";
  180. }
  181. if (needs.hasPlaneAlpha()) {
  182. fs << "uniform float alphaPlane;";
  183. }
  184. if (needs.hasColorMatrix()) {
  185. fs << "uniform mat4 colorMatrix;";
  186. }
  187. fs << "void main(void) {" << indent;
  188. if (needs.isTexturing()) {
  189. if (needs.getTextureMaskingTarget() != Key::TEXTURE_MASKING_OFF) {
  190. fs << "if (texture2D(samplerMask, outTexCoords).a <= maskAlphaThreshold) discard;"
  191. << "gl_FragColor = texture2D(sampler, outTexCoords);";
  192. } else {
  193. fs << "gl_FragColor = texture2D(sampler, outTexCoords);";
  194. }
  195. } else {
  196. fs << "gl_FragColor = color;";
  197. }
  198. if (needs.isOpaque()) {
  199. fs << "gl_FragColor.a = 1.0;";
  200. }
  201. if (needs.hasPlaneAlpha()) {
  202. // modulate the alpha value with planeAlpha
  203. if (needs.isPremultiplied()) {
  204. // ... and the color too if we're premultiplied
  205. fs << "gl_FragColor *= alphaPlane;";
  206. } else {
  207. fs << "gl_FragColor.a *= alphaPlane;";
  208. }
  209. }
  210. if (needs.hasColorMatrix()) {
  211. if (!needs.isOpaque() && needs.isPremultiplied()) {
  212. // un-premultiply if needed before linearization
  213. fs << "gl_FragColor.rgb = gl_FragColor.rgb/gl_FragColor.a;";
  214. }
  215. fs << "vec4 transformed = colorMatrix * vec4(gl_FragColor.rgb, 1);";
  216. fs << "gl_FragColor.rgb = transformed.rgb/transformed.a;";
  217. if (!needs.isOpaque() && needs.isPremultiplied()) {
  218. // and re-premultiply if needed after gamma correction
  219. fs << "gl_FragColor.rgb = gl_FragColor.rgb*gl_FragColor.a;";
  220. }
  221. }
  222. fs << dedent << "}";
  223. return fs.getString();
  224. }
  225. Program* ProgramCache::generateProgram(const Key& needs) {
  226. // vertex shader
  227. String8 vs = generateVertexShader(needs);
  228. // fragment shader
  229. String8 fs = generateFragmentShader(needs);
  230. Program* program = new Program(needs, vs.string(), fs.string());
  231. return program;
  232. }
  233. void ProgramCache::useProgram(const Description& description) {
  234. // generate the key for the shader based on the description
  235. Key needs(computeKey(description));
  236. // look-up the program in the cache
  237. Program* program = mCache.valueFor(needs);
  238. if (program == NULL) {
  239. // we didn't find our program, so generate one...
  240. nsecs_t time = -systemTime();
  241. program = generateProgram(needs);
  242. mCache.add(needs, program);
  243. time += systemTime();
  244. }
  245. // here we have a suitable program for this description
  246. if (program->isValid()) {
  247. program->use();
  248. program->setUniforms(description);
  249. }
  250. }
  251. } /* namespace android */