blob: d419e3eab38c765b61b5c5511443ec097695ce67 [file] [log] [blame]
Romain Guyac670c02010-07-27 17:39:27 -07001/*
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///////////////////////////////////////////////////////////////////////////////
Romain Guy707b2f72010-10-11 16:34:59 -070027// 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///////////////////////////////////////////////////////////////////////////////
Romain Guyac670c02010-07-27 17:39:27 -070035// Vertex shaders snippets
36///////////////////////////////////////////////////////////////////////////////
37
Romain Guyac670c02010-07-27 17:39:27 -070038const char* gVS_Header_Attributes =
39 "attribute vec4 position;\n";
40const char* gVS_Header_Attributes_TexCoords =
41 "attribute vec2 texCoords;\n";
Chet Haase99585ad2011-05-02 15:00:16 -070042const char* gVS_Header_Attributes_AAParameters =
43 "attribute float vtxWidth;\n"
44 "attribute float vtxLength;\n";
Romain Guyaa6c24c2011-04-28 18:40:04 -070045const char* gVS_Header_Uniforms_TextureTransform =
46 "uniform mat4 mainTextureTransform;\n";
Romain Guyac670c02010-07-27 17:39:27 -070047const char* gVS_Header_Uniforms =
48 "uniform mat4 transform;\n";
Romain Guyed6fcb02011-03-21 13:11:28 -070049const char* gVS_Header_Uniforms_IsPoint =
Romain Guy80bbfb12011-03-23 16:56:28 -070050 "uniform mediump float pointSize;\n";
Romain Guyee916f12010-09-20 17:53:08 -070051const char* gVS_Header_Uniforms_HasGradient[3] = {
52 // Linear
Romain Guyee916f12010-09-20 17:53:08 -070053 "uniform mat4 screenSpace;\n",
54 // Circular
Romain Guyddb80be2010-09-20 19:04:33 -070055 "uniform mat4 screenSpace;\n",
Romain Guyee916f12010-09-20 17:53:08 -070056 // Sweep
Romain Guyee916f12010-09-20 17:53:08 -070057 "uniform mat4 screenSpace;\n"
58};
Romain Guy889f8d12010-07-29 14:37:42 -070059const char* gVS_Header_Uniforms_HasBitmap =
60 "uniform mat4 textureTransform;\n"
Romain Guy80bbfb12011-03-23 16:56:28 -070061 "uniform mediump vec2 textureDimension;\n";
Romain Guyac670c02010-07-27 17:39:27 -070062const char* gVS_Header_Varyings_HasTexture =
63 "varying vec2 outTexCoords;\n";
Chet Haase99585ad2011-05-02 15:00:16 -070064const char* gVS_Header_Varyings_IsAA =
65 "varying float widthProportion;\n"
66 "varying float lengthProportion;\n";
Romain Guyac670c02010-07-27 17:39:27 -070067const char* gVS_Header_Varyings_HasBitmap =
68 "varying vec2 outBitmapTexCoords;\n";
Romain Guyed6fcb02011-03-21 13:11:28 -070069const char* gVS_Header_Varyings_PointHasBitmap =
70 "varying vec2 outPointBitmapTexCoords;\n";
Romain Guyee916f12010-09-20 17:53:08 -070071const char* gVS_Header_Varyings_HasGradient[3] = {
72 // Linear
Romain Guy7537f852010-10-11 14:38:28 -070073 "varying vec2 linear;\n",
Romain Guyee916f12010-09-20 17:53:08 -070074 // Circular
Romain Guyddb80be2010-09-20 19:04:33 -070075 "varying vec2 circular;\n",
Romain Guyee916f12010-09-20 17:53:08 -070076 // Sweep
77 "varying vec2 sweep;\n"
78};
Romain Guyac670c02010-07-27 17:39:27 -070079const char* gVS_Main =
80 "\nvoid main(void) {\n";
81const char* gVS_Main_OutTexCoords =
82 " outTexCoords = texCoords;\n";
Romain Guyaa6c24c2011-04-28 18:40:04 -070083const char* gVS_Main_OutTransformedTexCoords =
84 " outTexCoords = (mainTextureTransform * vec4(texCoords, 0.0, 1.0)).xy;\n";
Romain Guyee916f12010-09-20 17:53:08 -070085const char* gVS_Main_OutGradient[3] = {
86 // Linear
Romain Guy7537f852010-10-11 14:38:28 -070087 " linear = vec2((screenSpace * position).x, 0.5);\n",
Romain Guyee916f12010-09-20 17:53:08 -070088 // Circular
Romain Guy14830942010-10-07 15:07:45 -070089 " circular = (screenSpace * position).xy;\n",
Romain Guyee916f12010-09-20 17:53:08 -070090 // Sweep
Romain Guy14830942010-10-07 15:07:45 -070091 " sweep = (screenSpace * position).xy;\n"
Romain Guyee916f12010-09-20 17:53:08 -070092};
Romain Guy889f8d12010-07-29 14:37:42 -070093const char* gVS_Main_OutBitmapTexCoords =
Romain Guy707b2f72010-10-11 16:34:59 -070094 " outBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n";
Romain Guyed6fcb02011-03-21 13:11:28 -070095const char* gVS_Main_OutPointBitmapTexCoords =
96 " outPointBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n";
Romain Guyac670c02010-07-27 17:39:27 -070097const char* gVS_Main_Position =
98 " gl_Position = transform * position;\n";
Romain Guyed6fcb02011-03-21 13:11:28 -070099const char* gVS_Main_PointSize =
100 " gl_PointSize = pointSize;\n";
Chet Haase99585ad2011-05-02 15:00:16 -0700101const char* gVS_Main_AA =
102 " widthProportion = vtxWidth;\n"
103 " lengthProportion = vtxLength;\n";
Romain Guyac670c02010-07-27 17:39:27 -0700104const char* gVS_Footer =
105 "}\n\n";
106
107///////////////////////////////////////////////////////////////////////////////
108// Fragment shaders snippets
109///////////////////////////////////////////////////////////////////////////////
110
Romain Guya5aed0d2010-09-09 14:42:43 -0700111const char* gFS_Header_Extension_FramebufferFetch =
112 "#extension GL_NV_shader_framebuffer_fetch : enable\n\n";
Romain Guyaa6c24c2011-04-28 18:40:04 -0700113const char* gFS_Header_Extension_ExternalTexture =
114 "#extension GL_OES_EGL_image_external : require\n\n";
Romain Guyac670c02010-07-27 17:39:27 -0700115const char* gFS_Header =
116 "precision mediump float;\n\n";
117const char* gFS_Uniforms_Color =
118 "uniform vec4 color;\n";
Chet Haase99585ad2011-05-02 15:00:16 -0700119const char* gFS_Uniforms_AA =
Chet Haase5b0200b2011-04-13 17:58:08 -0700120 "uniform float boundaryWidth;\n"
Chet Haase99585ad2011-05-02 15:00:16 -0700121 "uniform float inverseBoundaryWidth;\n"
122 "uniform float boundaryLength;\n"
123 "uniform float inverseBoundaryLength;\n";
Romain Guyed6fcb02011-03-21 13:11:28 -0700124const char* gFS_Header_Uniforms_PointHasBitmap =
125 "uniform vec2 textureDimension;\n"
126 "uniform float pointSize;\n";
Romain Guyac670c02010-07-27 17:39:27 -0700127const char* gFS_Uniforms_TextureSampler =
128 "uniform sampler2D sampler;\n";
Romain Guyaa6c24c2011-04-28 18:40:04 -0700129const char* gFS_Uniforms_ExternalTextureSampler =
130 "uniform samplerExternalOES sampler;\n";
Romain Guyee916f12010-09-20 17:53:08 -0700131const char* gFS_Uniforms_GradientSampler[3] = {
132 // Linear
133 "uniform sampler2D gradientSampler;\n",
134 // Circular
135 "uniform sampler2D gradientSampler;\n",
136 // Sweep
137 "uniform sampler2D gradientSampler;\n"
138};
Romain Guyac670c02010-07-27 17:39:27 -0700139const char* gFS_Uniforms_BitmapSampler =
140 "uniform sampler2D bitmapSampler;\n";
141const char* gFS_Uniforms_ColorOp[4] = {
142 // None
143 "",
144 // Matrix
145 "uniform mat4 colorMatrix;\n"
146 "uniform vec4 colorMatrixVector;\n",
147 // Lighting
Romain Guydb1938e2010-08-02 18:50:22 -0700148 "uniform vec4 lightingMul;\n"
149 "uniform vec4 lightingAdd;\n",
Romain Guyac670c02010-07-27 17:39:27 -0700150 // PorterDuff
Romain Guydb1938e2010-08-02 18:50:22 -0700151 "uniform vec4 colorBlend;\n"
Romain Guyac670c02010-07-27 17:39:27 -0700152};
153const char* gFS_Main =
154 "\nvoid main(void) {\n"
Romain Guy7fbcc042010-08-04 15:40:07 -0700155 " lowp vec4 fragColor;\n";
Romain Guy707b2f72010-10-11 16:34:59 -0700156
Romain Guyed6fcb02011-03-21 13:11:28 -0700157const char* gFS_Main_PointBitmapTexCoords =
158 " vec2 outBitmapTexCoords = outPointBitmapTexCoords + "
159 "((gl_PointCoord - vec2(0.5, 0.5)) * textureDimension * vec2(pointSize, pointSize));\n";
160
Romain Guy707b2f72010-10-11 16:34:59 -0700161// Fast cases
162const char* gFS_Fast_SingleColor =
163 "\nvoid main(void) {\n"
164 " gl_FragColor = color;\n"
165 "}\n\n";
166const char* gFS_Fast_SingleTexture =
167 "\nvoid main(void) {\n"
168 " gl_FragColor = texture2D(sampler, outTexCoords);\n"
169 "}\n\n";
170const char* gFS_Fast_SingleModulateTexture =
171 "\nvoid main(void) {\n"
172 " gl_FragColor = color.a * texture2D(sampler, outTexCoords);\n"
173 "}\n\n";
174const char* gFS_Fast_SingleA8Texture =
175 "\nvoid main(void) {\n"
Romain Guy9db91242010-10-12 13:13:09 -0700176 " gl_FragColor = texture2D(sampler, outTexCoords);\n"
Romain Guy707b2f72010-10-11 16:34:59 -0700177 "}\n\n";
178const char* gFS_Fast_SingleModulateA8Texture =
179 "\nvoid main(void) {\n"
180 " gl_FragColor = color * texture2D(sampler, outTexCoords).a;\n"
181 "}\n\n";
182const char* gFS_Fast_SingleGradient =
183 "\nvoid main(void) {\n"
184 " gl_FragColor = texture2D(gradientSampler, linear);\n"
185 "}\n\n";
186const char* gFS_Fast_SingleModulateGradient =
187 "\nvoid main(void) {\n"
188 " gl_FragColor = color.a * texture2D(gradientSampler, linear);\n"
189 "}\n\n";
190
191// General case
Romain Guyac670c02010-07-27 17:39:27 -0700192const char* gFS_Main_FetchColor =
193 " fragColor = color;\n";
Romain Guy740bf2b2011-04-26 15:33:10 -0700194const char* gFS_Main_ModulateColor =
195 " fragColor *= color.a;\n";
Chet Haase99585ad2011-05-02 15:00:16 -0700196const char* gFS_Main_AccountForAA =
197 " if (widthProportion < boundaryWidth) {\n"
198 " fragColor *= (widthProportion * inverseBoundaryWidth);\n"
199 " } else if (widthProportion > (1.0 - boundaryWidth)) {\n"
200 " fragColor *= ((1.0 - widthProportion) * inverseBoundaryWidth);\n"
201 " }\n"
202 " if (lengthProportion < boundaryLength) {\n"
203 " fragColor *= (lengthProportion * inverseBoundaryLength);\n"
204 " } else if (lengthProportion > (1.0 - boundaryLength)) {\n"
205 " fragColor *= ((1.0 - lengthProportion) * inverseBoundaryLength);\n"
Chet Haase5b0200b2011-04-13 17:58:08 -0700206 " }\n";
Romain Guy707b2f72010-10-11 16:34:59 -0700207const char* gFS_Main_FetchTexture[2] = {
208 // Don't modulate
209 " fragColor = texture2D(sampler, outTexCoords);\n",
210 // Modulate
211 " fragColor = color * texture2D(sampler, outTexCoords);\n"
212};
213const char* gFS_Main_FetchA8Texture[2] = {
214 // Don't modulate
Romain Guy9db91242010-10-12 13:13:09 -0700215 " fragColor = texture2D(sampler, outTexCoords);\n",
Romain Guy707b2f72010-10-11 16:34:59 -0700216 // Modulate
217 " fragColor = color * texture2D(sampler, outTexCoords).a;\n"
218};
Romain Guyee916f12010-09-20 17:53:08 -0700219const char* gFS_Main_FetchGradient[3] = {
220 // Linear
Romain Guy7537f852010-10-11 14:38:28 -0700221 " vec4 gradientColor = texture2D(gradientSampler, linear);\n",
Romain Guyee916f12010-09-20 17:53:08 -0700222 // Circular
Romain Guy14830942010-10-07 15:07:45 -0700223 " float index = length(circular);\n"
Romain Guyddb80be2010-09-20 19:04:33 -0700224 " vec4 gradientColor = texture2D(gradientSampler, vec2(index, 0.5));\n",
Romain Guyee916f12010-09-20 17:53:08 -0700225 // Sweep
226 " float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
227 " vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n"
228};
Romain Guyac670c02010-07-27 17:39:27 -0700229const char* gFS_Main_FetchBitmap =
230 " vec4 bitmapColor = texture2D(bitmapSampler, outBitmapTexCoords);\n";
Romain Guy889f8d12010-07-29 14:37:42 -0700231const char* gFS_Main_FetchBitmapNpot =
232 " vec4 bitmapColor = texture2D(bitmapSampler, wrap(outBitmapTexCoords));\n";
Romain Guyac670c02010-07-27 17:39:27 -0700233const char* gFS_Main_BlendShadersBG =
Romain Guyac670c02010-07-27 17:39:27 -0700234 " fragColor = blendShaders(gradientColor, bitmapColor)";
Romain Guy06f96e22010-07-30 19:18:16 -0700235const char* gFS_Main_BlendShadersGB =
236 " fragColor = blendShaders(bitmapColor, gradientColor)";
Romain Guy707b2f72010-10-11 16:34:59 -0700237const char* gFS_Main_BlendShaders_Modulate[3] = {
238 // Don't modulate
239 ";\n",
240 // Modulate
241 " * fragColor.a;\n",
242 // Modulate with alpha 8 texture
243 " * texture2D(sampler, outTexCoords).a;\n"
244};
245const char* gFS_Main_GradientShader_Modulate[3] = {
246 // Don't modulate
247 " fragColor = gradientColor;\n",
248 // Modulate
249 " fragColor = gradientColor * fragColor.a;\n",
250 // Modulate with alpha 8 texture
251 " fragColor = gradientColor * texture2D(sampler, outTexCoords).a;\n"
252 };
253const char* gFS_Main_BitmapShader_Modulate[3] = {
254 // Don't modulate
255 " fragColor = bitmapColor;\n",
256 // Modulate
257 " fragColor = bitmapColor * fragColor.a;\n",
258 // Modulate with alpha 8 texture
259 " fragColor = bitmapColor * texture2D(sampler, outTexCoords).a;\n"
260 };
Romain Guyac670c02010-07-27 17:39:27 -0700261const char* gFS_Main_FragColor =
262 " gl_FragColor = fragColor;\n";
Romain Guya5aed0d2010-09-09 14:42:43 -0700263const char* gFS_Main_FragColor_Blend =
264 " gl_FragColor = blendFramebuffer(fragColor, gl_LastFragColor);\n";
Romain Guyf607bdc2010-09-10 19:20:06 -0700265const char* gFS_Main_FragColor_Blend_Swap =
266 " gl_FragColor = blendFramebuffer(gl_LastFragColor, fragColor);\n";
Romain Guyac670c02010-07-27 17:39:27 -0700267const char* gFS_Main_ApplyColorOp[4] = {
268 // None
269 "",
270 // Matrix
Romain Guydb1938e2010-08-02 18:50:22 -0700271 // TODO: Fix premultiplied alpha computations for color matrix
Romain Guyac670c02010-07-27 17:39:27 -0700272 " fragColor *= colorMatrix;\n"
Romain Guydb1938e2010-08-02 18:50:22 -0700273 " fragColor += colorMatrixVector;\n"
274 " fragColor.rgb *= fragColor.a;\n",
Romain Guyac670c02010-07-27 17:39:27 -0700275 // Lighting
Romain Guydb1938e2010-08-02 18:50:22 -0700276 " float lightingAlpha = fragColor.a;\n"
277 " fragColor = min(fragColor * lightingMul + (lightingAdd * lightingAlpha), lightingAlpha);\n"
278 " fragColor.a = lightingAlpha;\n",
Romain Guyac670c02010-07-27 17:39:27 -0700279 // PorterDuff
280 " fragColor = blendColors(colorBlend, fragColor);\n"
281};
282const char* gFS_Footer =
283 "}\n\n";
284
285///////////////////////////////////////////////////////////////////////////////
286// PorterDuff snippets
287///////////////////////////////////////////////////////////////////////////////
288
Romain Guy48daa542010-08-10 19:21:34 -0700289const char* gBlendOps[18] = {
Romain Guyac670c02010-07-27 17:39:27 -0700290 // Clear
291 "return vec4(0.0, 0.0, 0.0, 0.0);\n",
292 // Src
293 "return src;\n",
294 // Dst
295 "return dst;\n",
296 // SrcOver
Romain Guy06f96e22010-07-30 19:18:16 -0700297 "return src + dst * (1.0 - src.a);\n",
Romain Guyac670c02010-07-27 17:39:27 -0700298 // DstOver
Romain Guy06f96e22010-07-30 19:18:16 -0700299 "return dst + src * (1.0 - dst.a);\n",
Romain Guyac670c02010-07-27 17:39:27 -0700300 // SrcIn
Romain Guy06f96e22010-07-30 19:18:16 -0700301 "return src * dst.a;\n",
Romain Guyac670c02010-07-27 17:39:27 -0700302 // DstIn
Romain Guy06f96e22010-07-30 19:18:16 -0700303 "return dst * src.a;\n",
Romain Guyac670c02010-07-27 17:39:27 -0700304 // SrcOut
Romain Guy06f96e22010-07-30 19:18:16 -0700305 "return src * (1.0 - dst.a);\n",
Romain Guyac670c02010-07-27 17:39:27 -0700306 // DstOut
Romain Guy06f96e22010-07-30 19:18:16 -0700307 "return dst * (1.0 - src.a);\n",
Romain Guyac670c02010-07-27 17:39:27 -0700308 // SrcAtop
309 "return vec4(src.rgb * dst.a + (1.0 - src.a) * dst.rgb, dst.a);\n",
310 // DstAtop
311 "return vec4(dst.rgb * src.a + (1.0 - dst.a) * src.rgb, src.a);\n",
312 // Xor
Romain Guy48daa542010-08-10 19:21:34 -0700313 "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb, "
Romain Guyac670c02010-07-27 17:39:27 -0700314 "src.a + dst.a - 2.0 * src.a * dst.a);\n",
Romain Guy48daa542010-08-10 19:21:34 -0700315 // Add
316 "return min(src + dst, 1.0);\n",
317 // Multiply
318 "return src * dst;\n",
319 // Screen
320 "return src + dst - src * dst;\n",
321 // Overlay
322 "return clamp(vec4(mix("
323 "2.0 * src.rgb * dst.rgb + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), "
324 "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), "
325 "step(dst.a, 2.0 * dst.rgb)), "
326 "src.a + dst.a - src.a * dst.a), 0.0, 1.0);\n",
327 // Darken
328 "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + "
329 "min(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n",
330 // Lighten
331 "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + "
332 "max(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n",
Romain Guyac670c02010-07-27 17:39:27 -0700333};
334
335///////////////////////////////////////////////////////////////////////////////
336// Constructors/destructors
337///////////////////////////////////////////////////////////////////////////////
338
339ProgramCache::ProgramCache() {
340}
341
342ProgramCache::~ProgramCache() {
343 clear();
344}
345
346///////////////////////////////////////////////////////////////////////////////
347// Cache management
348///////////////////////////////////////////////////////////////////////////////
349
350void ProgramCache::clear() {
Romain Guy67f27952010-12-07 20:09:23 -0800351 PROGRAM_LOGD("Clearing program cache");
352
Romain Guyac670c02010-07-27 17:39:27 -0700353 size_t count = mCache.size();
354 for (size_t i = 0; i < count; i++) {
355 delete mCache.valueAt(i);
356 }
357 mCache.clear();
358}
359
360Program* ProgramCache::get(const ProgramDescription& description) {
361 programid key = description.key();
362 ssize_t index = mCache.indexOfKey(key);
363 Program* program = NULL;
364 if (index < 0) {
Romain Guyee916f12010-09-20 17:53:08 -0700365 description.log("Could not find program");
Romain Guyac670c02010-07-27 17:39:27 -0700366 program = generateProgram(description, key);
367 mCache.add(key, program);
368 } else {
369 program = mCache.valueAt(index);
370 }
371 return program;
372}
373
374///////////////////////////////////////////////////////////////////////////////
375// Program generation
376///////////////////////////////////////////////////////////////////////////////
377
378Program* ProgramCache::generateProgram(const ProgramDescription& description, programid key) {
379 String8 vertexShader = generateVertexShader(description);
380 String8 fragmentShader = generateFragmentShader(description);
381
382 Program* program = new Program(vertexShader.string(), fragmentShader.string());
383 return program;
384}
385
386String8 ProgramCache::generateVertexShader(const ProgramDescription& description) {
387 // Add attributes
388 String8 shader(gVS_Header_Attributes);
Romain Guyaa6c24c2011-04-28 18:40:04 -0700389 if (description.hasTexture || description.hasExternalTexture) {
Romain Guyac670c02010-07-27 17:39:27 -0700390 shader.append(gVS_Header_Attributes_TexCoords);
391 }
Chet Haase99585ad2011-05-02 15:00:16 -0700392 if (description.isAA) {
393 shader.append(gVS_Header_Attributes_AAParameters);
Chet Haase5b0200b2011-04-13 17:58:08 -0700394 }
Romain Guyac670c02010-07-27 17:39:27 -0700395 // Uniforms
396 shader.append(gVS_Header_Uniforms);
Romain Guy8f0095c2011-05-02 17:24:22 -0700397 if (description.hasTextureTransform) {
Romain Guyaa6c24c2011-04-28 18:40:04 -0700398 shader.append(gVS_Header_Uniforms_TextureTransform);
399 }
Romain Guyac670c02010-07-27 17:39:27 -0700400 if (description.hasGradient) {
Romain Guyee916f12010-09-20 17:53:08 -0700401 shader.append(gVS_Header_Uniforms_HasGradient[description.gradientType]);
Romain Guyac670c02010-07-27 17:39:27 -0700402 }
Romain Guy889f8d12010-07-29 14:37:42 -0700403 if (description.hasBitmap) {
404 shader.append(gVS_Header_Uniforms_HasBitmap);
405 }
Romain Guyed6fcb02011-03-21 13:11:28 -0700406 if (description.isPoint) {
407 shader.append(gVS_Header_Uniforms_IsPoint);
408 }
Romain Guyac670c02010-07-27 17:39:27 -0700409 // Varyings
Romain Guyaa6c24c2011-04-28 18:40:04 -0700410 if (description.hasTexture || description.hasExternalTexture) {
Romain Guyac670c02010-07-27 17:39:27 -0700411 shader.append(gVS_Header_Varyings_HasTexture);
412 }
Chet Haase99585ad2011-05-02 15:00:16 -0700413 if (description.isAA) {
414 shader.append(gVS_Header_Varyings_IsAA);
Chet Haase5b0200b2011-04-13 17:58:08 -0700415 }
Romain Guyac670c02010-07-27 17:39:27 -0700416 if (description.hasGradient) {
Romain Guyee916f12010-09-20 17:53:08 -0700417 shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]);
Romain Guyac670c02010-07-27 17:39:27 -0700418 }
419 if (description.hasBitmap) {
Romain Guyed6fcb02011-03-21 13:11:28 -0700420 shader.append(description.isPoint ?
421 gVS_Header_Varyings_PointHasBitmap :
422 gVS_Header_Varyings_HasBitmap);
Romain Guyac670c02010-07-27 17:39:27 -0700423 }
424
425 // Begin the shader
426 shader.append(gVS_Main); {
Romain Guy8f0095c2011-05-02 17:24:22 -0700427 if (description.hasTextureTransform) {
Romain Guyaa6c24c2011-04-28 18:40:04 -0700428 shader.append(gVS_Main_OutTransformedTexCoords);
Romain Guy8f0095c2011-05-02 17:24:22 -0700429 } else if (description.hasTexture || description.hasExternalTexture) {
430 shader.append(gVS_Main_OutTexCoords);
Romain Guyaa6c24c2011-04-28 18:40:04 -0700431 }
Chet Haase99585ad2011-05-02 15:00:16 -0700432 if (description.isAA) {
433 shader.append(gVS_Main_AA);
Chet Haase5b0200b2011-04-13 17:58:08 -0700434 }
Romain Guyac670c02010-07-27 17:39:27 -0700435 if (description.hasGradient) {
Romain Guyee916f12010-09-20 17:53:08 -0700436 shader.append(gVS_Main_OutGradient[description.gradientType]);
Romain Guyac670c02010-07-27 17:39:27 -0700437 }
Romain Guy889f8d12010-07-29 14:37:42 -0700438 if (description.hasBitmap) {
Romain Guyed6fcb02011-03-21 13:11:28 -0700439 shader.append(description.isPoint ?
440 gVS_Main_OutPointBitmapTexCoords :
441 gVS_Main_OutBitmapTexCoords);
442 }
443 if (description.isPoint) {
444 shader.append(gVS_Main_PointSize);
Romain Guy889f8d12010-07-29 14:37:42 -0700445 }
Romain Guyac670c02010-07-27 17:39:27 -0700446 // Output transformed position
447 shader.append(gVS_Main_Position);
448 }
449 // End the shader
450 shader.append(gVS_Footer);
451
452 PROGRAM_LOGD("*** Generated vertex shader:\n\n%s", shader.string());
453
454 return shader;
455}
456
457String8 ProgramCache::generateFragmentShader(const ProgramDescription& description) {
458 // Set the default precision
Romain Guya5aed0d2010-09-09 14:42:43 -0700459 String8 shader;
460
Romain Guy707b2f72010-10-11 16:34:59 -0700461 const bool blendFramebuffer = description.framebufferMode >= SkXfermode::kPlus_Mode;
Romain Guya5aed0d2010-09-09 14:42:43 -0700462 if (blendFramebuffer) {
463 shader.append(gFS_Header_Extension_FramebufferFetch);
464 }
Romain Guyaa6c24c2011-04-28 18:40:04 -0700465 if (description.hasExternalTexture) {
466 shader.append(gFS_Header_Extension_ExternalTexture);
467 }
Romain Guya5aed0d2010-09-09 14:42:43 -0700468
469 shader.append(gFS_Header);
Romain Guyac670c02010-07-27 17:39:27 -0700470
471 // Varyings
Romain Guyaa6c24c2011-04-28 18:40:04 -0700472 if (description.hasTexture || description.hasExternalTexture) {
Romain Guyac670c02010-07-27 17:39:27 -0700473 shader.append(gVS_Header_Varyings_HasTexture);
474 }
Chet Haase99585ad2011-05-02 15:00:16 -0700475 if (description.isAA) {
476 shader.append(gVS_Header_Varyings_IsAA);
Chet Haase5b0200b2011-04-13 17:58:08 -0700477 }
Romain Guyac670c02010-07-27 17:39:27 -0700478 if (description.hasGradient) {
Romain Guyee916f12010-09-20 17:53:08 -0700479 shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]);
Romain Guyac670c02010-07-27 17:39:27 -0700480 }
481 if (description.hasBitmap) {
Romain Guyed6fcb02011-03-21 13:11:28 -0700482 shader.append(description.isPoint ?
483 gVS_Header_Varyings_PointHasBitmap :
484 gVS_Header_Varyings_HasBitmap);
Romain Guyac670c02010-07-27 17:39:27 -0700485 }
486
Romain Guyac670c02010-07-27 17:39:27 -0700487 // Uniforms
Romain Guy707b2f72010-10-11 16:34:59 -0700488 int modulateOp = MODULATE_OP_NO_MODULATE;
Romain Guyaa6c24c2011-04-28 18:40:04 -0700489 const bool singleColor = !description.hasTexture && !description.hasExternalTexture &&
Romain Guy707b2f72010-10-11 16:34:59 -0700490 !description.hasGradient && !description.hasBitmap;
491
492 if (description.modulate || singleColor) {
493 shader.append(gFS_Uniforms_Color);
494 if (!singleColor) modulateOp = MODULATE_OP_MODULATE;
495 }
Romain Guyac670c02010-07-27 17:39:27 -0700496 if (description.hasTexture) {
497 shader.append(gFS_Uniforms_TextureSampler);
Romain Guy8f0095c2011-05-02 17:24:22 -0700498 } else if (description.hasExternalTexture) {
Romain Guyaa6c24c2011-04-28 18:40:04 -0700499 shader.append(gFS_Uniforms_ExternalTextureSampler);
500 }
Chet Haase99585ad2011-05-02 15:00:16 -0700501 if (description.isAA) {
502 shader.append(gFS_Uniforms_AA);
Chet Haase5b0200b2011-04-13 17:58:08 -0700503 }
Romain Guyac670c02010-07-27 17:39:27 -0700504 if (description.hasGradient) {
Romain Guyee916f12010-09-20 17:53:08 -0700505 shader.append(gFS_Uniforms_GradientSampler[description.gradientType]);
Romain Guyac670c02010-07-27 17:39:27 -0700506 }
Romain Guyed6fcb02011-03-21 13:11:28 -0700507 if (description.hasBitmap && description.isPoint) {
508 shader.append(gFS_Header_Uniforms_PointHasBitmap);
509 }
Romain Guy707b2f72010-10-11 16:34:59 -0700510
511 // Optimization for common cases
Chet Haase99585ad2011-05-02 15:00:16 -0700512 if (!description.isAA && !blendFramebuffer &&
Chet Haase5b0200b2011-04-13 17:58:08 -0700513 description.colorOp == ProgramDescription::kColorNone && !description.isPoint) {
Romain Guy707b2f72010-10-11 16:34:59 -0700514 bool fast = false;
515
516 const bool noShader = !description.hasGradient && !description.hasBitmap;
Romain Guyaa6c24c2011-04-28 18:40:04 -0700517 const bool singleTexture = (description.hasTexture || description.hasExternalTexture) &&
Romain Guy707b2f72010-10-11 16:34:59 -0700518 !description.hasAlpha8Texture && noShader;
519 const bool singleA8Texture = description.hasTexture &&
520 description.hasAlpha8Texture && noShader;
Romain Guyaa6c24c2011-04-28 18:40:04 -0700521 const bool singleGradient = !description.hasTexture && !description.hasExternalTexture &&
Romain Guy707b2f72010-10-11 16:34:59 -0700522 description.hasGradient && !description.hasBitmap &&
523 description.gradientType == ProgramDescription::kGradientLinear;
524
525 if (singleColor) {
526 shader.append(gFS_Fast_SingleColor);
527 fast = true;
528 } else if (singleTexture) {
529 if (!description.modulate) {
530 shader.append(gFS_Fast_SingleTexture);
531 } else {
532 shader.append(gFS_Fast_SingleModulateTexture);
533 }
534 fast = true;
535 } else if (singleA8Texture) {
536 if (!description.modulate) {
537 shader.append(gFS_Fast_SingleA8Texture);
538 } else {
539 shader.append(gFS_Fast_SingleModulateA8Texture);
540 }
541 fast = true;
542 } else if (singleGradient) {
543 if (!description.modulate) {
544 shader.append(gFS_Fast_SingleGradient);
545 } else {
546 shader.append(gFS_Fast_SingleModulateGradient);
547 }
548 fast = true;
549 }
550
551 if (fast) {
Romain Guyc15008e2010-11-10 11:59:15 -0800552#if DEBUG_PROGRAMS
Romain Guy707b2f72010-10-11 16:34:59 -0700553 PROGRAM_LOGD("*** Fast case:\n");
554 PROGRAM_LOGD("*** Generated fragment shader:\n\n");
555 printLongString(shader);
Romain Guyc15008e2010-11-10 11:59:15 -0800556#endif
Romain Guy707b2f72010-10-11 16:34:59 -0700557
558 return shader;
559 }
560 }
561
Romain Guyac670c02010-07-27 17:39:27 -0700562 if (description.hasBitmap) {
563 shader.append(gFS_Uniforms_BitmapSampler);
564 }
565 shader.append(gFS_Uniforms_ColorOp[description.colorOp]);
566
567 // Generate required functions
568 if (description.hasGradient && description.hasBitmap) {
Romain Guy48daa542010-08-10 19:21:34 -0700569 generateBlend(shader, "blendShaders", description.shadersMode);
Romain Guyac670c02010-07-27 17:39:27 -0700570 }
571 if (description.colorOp == ProgramDescription::kColorBlend) {
Romain Guy48daa542010-08-10 19:21:34 -0700572 generateBlend(shader, "blendColors", description.colorMode);
Romain Guyac670c02010-07-27 17:39:27 -0700573 }
Romain Guya5aed0d2010-09-09 14:42:43 -0700574 if (blendFramebuffer) {
575 generateBlend(shader, "blendFramebuffer", description.framebufferMode);
576 }
Romain Guy889f8d12010-07-29 14:37:42 -0700577 if (description.isBitmapNpot) {
578 generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT);
579 }
Romain Guyac670c02010-07-27 17:39:27 -0700580
581 // Begin the shader
582 shader.append(gFS_Main); {
583 // Stores the result in fragColor directly
Romain Guyaa6c24c2011-04-28 18:40:04 -0700584 if (description.hasTexture || description.hasExternalTexture) {
Romain Guyac670c02010-07-27 17:39:27 -0700585 if (description.hasAlpha8Texture) {
Romain Guy707b2f72010-10-11 16:34:59 -0700586 if (!description.hasGradient && !description.hasBitmap) {
587 shader.append(gFS_Main_FetchA8Texture[modulateOp]);
588 }
Romain Guyac670c02010-07-27 17:39:27 -0700589 } else {
Romain Guy707b2f72010-10-11 16:34:59 -0700590 shader.append(gFS_Main_FetchTexture[modulateOp]);
Romain Guyac670c02010-07-27 17:39:27 -0700591 }
592 } else {
Romain Guy707b2f72010-10-11 16:34:59 -0700593 if ((!description.hasGradient && !description.hasBitmap) || description.modulate) {
594 shader.append(gFS_Main_FetchColor);
595 }
Romain Guyac670c02010-07-27 17:39:27 -0700596 }
Chet Haase99585ad2011-05-02 15:00:16 -0700597 if (description.isAA) {
598 shader.append(gFS_Main_AccountForAA);
Chet Haase5b0200b2011-04-13 17:58:08 -0700599 }
Romain Guyac670c02010-07-27 17:39:27 -0700600 if (description.hasGradient) {
Romain Guyee916f12010-09-20 17:53:08 -0700601 shader.append(gFS_Main_FetchGradient[description.gradientType]);
Romain Guyac670c02010-07-27 17:39:27 -0700602 }
603 if (description.hasBitmap) {
Romain Guyed6fcb02011-03-21 13:11:28 -0700604 if (description.isPoint) {
605 shader.append(gFS_Main_PointBitmapTexCoords);
606 }
Romain Guy889f8d12010-07-29 14:37:42 -0700607 if (!description.isBitmapNpot) {
608 shader.append(gFS_Main_FetchBitmap);
609 } else {
610 shader.append(gFS_Main_FetchBitmapNpot);
611 }
Romain Guyac670c02010-07-27 17:39:27 -0700612 }
Romain Guy740bf2b2011-04-26 15:33:10 -0700613 bool applyModulate = false;
Romain Guyac670c02010-07-27 17:39:27 -0700614 // Case when we have two shaders set
615 if (description.hasGradient && description.hasBitmap) {
Romain Guy707b2f72010-10-11 16:34:59 -0700616 int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp;
Romain Guyac670c02010-07-27 17:39:27 -0700617 if (description.isBitmapFirst) {
618 shader.append(gFS_Main_BlendShadersBG);
619 } else {
620 shader.append(gFS_Main_BlendShadersGB);
621 }
Romain Guy707b2f72010-10-11 16:34:59 -0700622 shader.append(gFS_Main_BlendShaders_Modulate[op]);
Romain Guy740bf2b2011-04-26 15:33:10 -0700623 applyModulate = true;
Romain Guy889f8d12010-07-29 14:37:42 -0700624 } else {
625 if (description.hasGradient) {
Romain Guy707b2f72010-10-11 16:34:59 -0700626 int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp;
627 shader.append(gFS_Main_GradientShader_Modulate[op]);
Romain Guy740bf2b2011-04-26 15:33:10 -0700628 applyModulate = true;
Romain Guy889f8d12010-07-29 14:37:42 -0700629 } else if (description.hasBitmap) {
Romain Guy707b2f72010-10-11 16:34:59 -0700630 int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp;
631 shader.append(gFS_Main_BitmapShader_Modulate[op]);
Romain Guy740bf2b2011-04-26 15:33:10 -0700632 applyModulate = true;
Romain Guy889f8d12010-07-29 14:37:42 -0700633 }
Romain Guyac670c02010-07-27 17:39:27 -0700634 }
Romain Guy740bf2b2011-04-26 15:33:10 -0700635 if (description.modulate && applyModulate) {
636 shader.append(gFS_Main_ModulateColor);
637 }
Romain Guyac670c02010-07-27 17:39:27 -0700638 // Apply the color op if needed
639 shader.append(gFS_Main_ApplyColorOp[description.colorOp]);
640 // Output the fragment
Romain Guya5aed0d2010-09-09 14:42:43 -0700641 if (!blendFramebuffer) {
642 shader.append(gFS_Main_FragColor);
643 } else {
Romain Guyf607bdc2010-09-10 19:20:06 -0700644 shader.append(!description.swapSrcDst ?
645 gFS_Main_FragColor_Blend : gFS_Main_FragColor_Blend_Swap);
Romain Guya5aed0d2010-09-09 14:42:43 -0700646 }
Romain Guyac670c02010-07-27 17:39:27 -0700647 }
648 // End the shader
649 shader.append(gFS_Footer);
650
Romain Guyc15008e2010-11-10 11:59:15 -0800651#if DEBUG_PROGRAMS
Romain Guydb1938e2010-08-02 18:50:22 -0700652 PROGRAM_LOGD("*** Generated fragment shader:\n\n");
653 printLongString(shader);
Romain Guyc15008e2010-11-10 11:59:15 -0800654#endif
Romain Guydb1938e2010-08-02 18:50:22 -0700655
Romain Guyac670c02010-07-27 17:39:27 -0700656 return shader;
657}
658
Romain Guy48daa542010-08-10 19:21:34 -0700659void ProgramCache::generateBlend(String8& shader, const char* name, SkXfermode::Mode mode) {
Romain Guyac670c02010-07-27 17:39:27 -0700660 shader.append("\nvec4 ");
661 shader.append(name);
662 shader.append("(vec4 src, vec4 dst) {\n");
663 shader.append(" ");
Romain Guy48daa542010-08-10 19:21:34 -0700664 shader.append(gBlendOps[mode]);
Romain Guyac670c02010-07-27 17:39:27 -0700665 shader.append("}\n");
666}
667
Romain Guy889f8d12010-07-29 14:37:42 -0700668void ProgramCache::generateTextureWrap(String8& shader, GLenum wrapS, GLenum wrapT) {
669 shader.append("\nvec2 wrap(vec2 texCoords) {\n");
670 if (wrapS == GL_MIRRORED_REPEAT) {
671 shader.append(" float xMod2 = mod(texCoords.x, 2.0);\n");
672 shader.append(" if (xMod2 > 1.0) xMod2 = 2.0 - xMod2;\n");
673 }
674 if (wrapT == GL_MIRRORED_REPEAT) {
675 shader.append(" float yMod2 = mod(texCoords.y, 2.0);\n");
676 shader.append(" if (yMod2 > 1.0) yMod2 = 2.0 - yMod2;\n");
677 }
678 shader.append(" return vec2(");
679 switch (wrapS) {
Romain Guy61c8c9c2010-08-09 20:48:09 -0700680 case GL_CLAMP_TO_EDGE:
681 shader.append("texCoords.x");
682 break;
Romain Guy889f8d12010-07-29 14:37:42 -0700683 case GL_REPEAT:
684 shader.append("mod(texCoords.x, 1.0)");
685 break;
686 case GL_MIRRORED_REPEAT:
687 shader.append("xMod2");
688 break;
689 }
690 shader.append(", ");
691 switch (wrapT) {
Romain Guy61c8c9c2010-08-09 20:48:09 -0700692 case GL_CLAMP_TO_EDGE:
693 shader.append("texCoords.y");
694 break;
Romain Guy889f8d12010-07-29 14:37:42 -0700695 case GL_REPEAT:
696 shader.append("mod(texCoords.y, 1.0)");
697 break;
698 case GL_MIRRORED_REPEAT:
699 shader.append("yMod2");
700 break;
701 }
702 shader.append(");\n");
703 shader.append("}\n");
704}
705
Romain Guydb1938e2010-08-02 18:50:22 -0700706void ProgramCache::printLongString(const String8& shader) const {
707 ssize_t index = 0;
708 ssize_t lastIndex = 0;
709 const char* str = shader.string();
710 while ((index = shader.find("\n", index)) > -1) {
711 String8 line(str, index - lastIndex);
712 if (line.length() == 0) line.append("\n");
713 PROGRAM_LOGD("%s", line.string());
714 index++;
715 str += (index - lastIndex);
716 lastIndex = index;
717 }
718}
719
Romain Guyac670c02010-07-27 17:39:27 -0700720}; // namespace uirenderer
721}; // namespace android