blob: 0b6c7b5c64d281faa57c57cdc1483a496460c852 [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";
42const char* gVS_Header_Uniforms =
43 "uniform mat4 transform;\n";
Romain Guyee916f12010-09-20 17:53:08 -070044const char* gVS_Header_Uniforms_HasGradient[3] = {
45 // Linear
Romain Guyee916f12010-09-20 17:53:08 -070046 "uniform mat4 screenSpace;\n",
47 // Circular
Romain Guyddb80be2010-09-20 19:04:33 -070048 "uniform mat4 screenSpace;\n",
Romain Guyee916f12010-09-20 17:53:08 -070049 // Sweep
Romain Guyee916f12010-09-20 17:53:08 -070050 "uniform mat4 screenSpace;\n"
51};
Romain Guy889f8d12010-07-29 14:37:42 -070052const char* gVS_Header_Uniforms_HasBitmap =
53 "uniform mat4 textureTransform;\n"
54 "uniform vec2 textureDimension;\n";
Romain Guyac670c02010-07-27 17:39:27 -070055const char* gVS_Header_Varyings_HasTexture =
56 "varying vec2 outTexCoords;\n";
57const char* gVS_Header_Varyings_HasBitmap =
58 "varying vec2 outBitmapTexCoords;\n";
Romain Guyee916f12010-09-20 17:53:08 -070059const char* gVS_Header_Varyings_HasGradient[3] = {
60 // Linear
Romain Guy7537f852010-10-11 14:38:28 -070061 "varying vec2 linear;\n",
Romain Guyee916f12010-09-20 17:53:08 -070062 // Circular
Romain Guyddb80be2010-09-20 19:04:33 -070063 "varying vec2 circular;\n",
Romain Guyee916f12010-09-20 17:53:08 -070064 // Sweep
65 "varying vec2 sweep;\n"
66};
Romain Guyac670c02010-07-27 17:39:27 -070067const char* gVS_Main =
68 "\nvoid main(void) {\n";
69const char* gVS_Main_OutTexCoords =
70 " outTexCoords = texCoords;\n";
Romain Guyee916f12010-09-20 17:53:08 -070071const char* gVS_Main_OutGradient[3] = {
72 // Linear
Romain Guy7537f852010-10-11 14:38:28 -070073 " linear = vec2((screenSpace * position).x, 0.5);\n",
Romain Guyee916f12010-09-20 17:53:08 -070074 // Circular
Romain Guy14830942010-10-07 15:07:45 -070075 " circular = (screenSpace * position).xy;\n",
Romain Guyee916f12010-09-20 17:53:08 -070076 // Sweep
Romain Guy14830942010-10-07 15:07:45 -070077 " sweep = (screenSpace * position).xy;\n"
Romain Guyee916f12010-09-20 17:53:08 -070078};
Romain Guy889f8d12010-07-29 14:37:42 -070079const char* gVS_Main_OutBitmapTexCoords =
Romain Guy707b2f72010-10-11 16:34:59 -070080 " outBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n";
Romain Guyac670c02010-07-27 17:39:27 -070081const char* gVS_Main_Position =
82 " gl_Position = transform * position;\n";
83const char* gVS_Footer =
84 "}\n\n";
85
86///////////////////////////////////////////////////////////////////////////////
87// Fragment shaders snippets
88///////////////////////////////////////////////////////////////////////////////
89
Romain Guya5aed0d2010-09-09 14:42:43 -070090const char* gFS_Header_Extension_FramebufferFetch =
91 "#extension GL_NV_shader_framebuffer_fetch : enable\n\n";
Romain Guyac670c02010-07-27 17:39:27 -070092const char* gFS_Header =
93 "precision mediump float;\n\n";
94const char* gFS_Uniforms_Color =
95 "uniform vec4 color;\n";
96const char* gFS_Uniforms_TextureSampler =
97 "uniform sampler2D sampler;\n";
Romain Guyee916f12010-09-20 17:53:08 -070098const char* gFS_Uniforms_GradientSampler[3] = {
99 // Linear
100 "uniform sampler2D gradientSampler;\n",
101 // Circular
102 "uniform sampler2D gradientSampler;\n",
103 // Sweep
104 "uniform sampler2D gradientSampler;\n"
105};
Romain Guyac670c02010-07-27 17:39:27 -0700106const char* gFS_Uniforms_BitmapSampler =
107 "uniform sampler2D bitmapSampler;\n";
108const char* gFS_Uniforms_ColorOp[4] = {
109 // None
110 "",
111 // Matrix
112 "uniform mat4 colorMatrix;\n"
113 "uniform vec4 colorMatrixVector;\n",
114 // Lighting
Romain Guydb1938e2010-08-02 18:50:22 -0700115 "uniform vec4 lightingMul;\n"
116 "uniform vec4 lightingAdd;\n",
Romain Guyac670c02010-07-27 17:39:27 -0700117 // PorterDuff
Romain Guydb1938e2010-08-02 18:50:22 -0700118 "uniform vec4 colorBlend;\n"
Romain Guyac670c02010-07-27 17:39:27 -0700119};
120const char* gFS_Main =
121 "\nvoid main(void) {\n"
Romain Guy7fbcc042010-08-04 15:40:07 -0700122 " lowp vec4 fragColor;\n";
Romain Guy707b2f72010-10-11 16:34:59 -0700123
124// Fast cases
125const char* gFS_Fast_SingleColor =
126 "\nvoid main(void) {\n"
127 " gl_FragColor = color;\n"
128 "}\n\n";
129const char* gFS_Fast_SingleTexture =
130 "\nvoid main(void) {\n"
131 " gl_FragColor = texture2D(sampler, outTexCoords);\n"
132 "}\n\n";
133const char* gFS_Fast_SingleModulateTexture =
134 "\nvoid main(void) {\n"
135 " gl_FragColor = color.a * texture2D(sampler, outTexCoords);\n"
136 "}\n\n";
137const char* gFS_Fast_SingleA8Texture =
138 "\nvoid main(void) {\n"
Romain Guy9db91242010-10-12 13:13:09 -0700139 " gl_FragColor = texture2D(sampler, outTexCoords);\n"
Romain Guy707b2f72010-10-11 16:34:59 -0700140 "}\n\n";
141const char* gFS_Fast_SingleModulateA8Texture =
142 "\nvoid main(void) {\n"
143 " gl_FragColor = color * texture2D(sampler, outTexCoords).a;\n"
144 "}\n\n";
145const char* gFS_Fast_SingleGradient =
146 "\nvoid main(void) {\n"
147 " gl_FragColor = texture2D(gradientSampler, linear);\n"
148 "}\n\n";
149const char* gFS_Fast_SingleModulateGradient =
150 "\nvoid main(void) {\n"
151 " gl_FragColor = color.a * texture2D(gradientSampler, linear);\n"
152 "}\n\n";
153
154// General case
Romain Guyac670c02010-07-27 17:39:27 -0700155const char* gFS_Main_FetchColor =
156 " fragColor = color;\n";
Romain Guy707b2f72010-10-11 16:34:59 -0700157const char* gFS_Main_FetchTexture[2] = {
158 // Don't modulate
159 " fragColor = texture2D(sampler, outTexCoords);\n",
160 // Modulate
161 " fragColor = color * texture2D(sampler, outTexCoords);\n"
162};
163const char* gFS_Main_FetchA8Texture[2] = {
164 // Don't modulate
Romain Guy9db91242010-10-12 13:13:09 -0700165 " fragColor = texture2D(sampler, outTexCoords);\n",
Romain Guy707b2f72010-10-11 16:34:59 -0700166 // Modulate
167 " fragColor = color * texture2D(sampler, outTexCoords).a;\n"
168};
Romain Guyee916f12010-09-20 17:53:08 -0700169const char* gFS_Main_FetchGradient[3] = {
170 // Linear
Romain Guy7537f852010-10-11 14:38:28 -0700171 " vec4 gradientColor = texture2D(gradientSampler, linear);\n",
Romain Guyee916f12010-09-20 17:53:08 -0700172 // Circular
Romain Guy14830942010-10-07 15:07:45 -0700173 " float index = length(circular);\n"
Romain Guyddb80be2010-09-20 19:04:33 -0700174 " vec4 gradientColor = texture2D(gradientSampler, vec2(index, 0.5));\n",
Romain Guyee916f12010-09-20 17:53:08 -0700175 // Sweep
176 " float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
177 " vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n"
178};
Romain Guyac670c02010-07-27 17:39:27 -0700179const char* gFS_Main_FetchBitmap =
180 " vec4 bitmapColor = texture2D(bitmapSampler, outBitmapTexCoords);\n";
Romain Guy889f8d12010-07-29 14:37:42 -0700181const char* gFS_Main_FetchBitmapNpot =
182 " vec4 bitmapColor = texture2D(bitmapSampler, wrap(outBitmapTexCoords));\n";
Romain Guyac670c02010-07-27 17:39:27 -0700183const char* gFS_Main_BlendShadersBG =
Romain Guyac670c02010-07-27 17:39:27 -0700184 " fragColor = blendShaders(gradientColor, bitmapColor)";
Romain Guy06f96e22010-07-30 19:18:16 -0700185const char* gFS_Main_BlendShadersGB =
186 " fragColor = blendShaders(bitmapColor, gradientColor)";
Romain Guy707b2f72010-10-11 16:34:59 -0700187const char* gFS_Main_BlendShaders_Modulate[3] = {
188 // Don't modulate
189 ";\n",
190 // Modulate
191 " * fragColor.a;\n",
192 // Modulate with alpha 8 texture
193 " * texture2D(sampler, outTexCoords).a;\n"
194};
195const char* gFS_Main_GradientShader_Modulate[3] = {
196 // Don't modulate
197 " fragColor = gradientColor;\n",
198 // Modulate
199 " fragColor = gradientColor * fragColor.a;\n",
200 // Modulate with alpha 8 texture
201 " fragColor = gradientColor * texture2D(sampler, outTexCoords).a;\n"
202 };
203const char* gFS_Main_BitmapShader_Modulate[3] = {
204 // Don't modulate
205 " fragColor = bitmapColor;\n",
206 // Modulate
207 " fragColor = bitmapColor * fragColor.a;\n",
208 // Modulate with alpha 8 texture
209 " fragColor = bitmapColor * texture2D(sampler, outTexCoords).a;\n"
210 };
Romain Guyac670c02010-07-27 17:39:27 -0700211const char* gFS_Main_FragColor =
212 " gl_FragColor = fragColor;\n";
Romain Guya5aed0d2010-09-09 14:42:43 -0700213const char* gFS_Main_FragColor_Blend =
214 " gl_FragColor = blendFramebuffer(fragColor, gl_LastFragColor);\n";
Romain Guyf607bdc2010-09-10 19:20:06 -0700215const char* gFS_Main_FragColor_Blend_Swap =
216 " gl_FragColor = blendFramebuffer(gl_LastFragColor, fragColor);\n";
Romain Guyac670c02010-07-27 17:39:27 -0700217const char* gFS_Main_ApplyColorOp[4] = {
218 // None
219 "",
220 // Matrix
Romain Guydb1938e2010-08-02 18:50:22 -0700221 // TODO: Fix premultiplied alpha computations for color matrix
Romain Guyac670c02010-07-27 17:39:27 -0700222 " fragColor *= colorMatrix;\n"
Romain Guydb1938e2010-08-02 18:50:22 -0700223 " fragColor += colorMatrixVector;\n"
224 " fragColor.rgb *= fragColor.a;\n",
Romain Guyac670c02010-07-27 17:39:27 -0700225 // Lighting
Romain Guydb1938e2010-08-02 18:50:22 -0700226 " float lightingAlpha = fragColor.a;\n"
227 " fragColor = min(fragColor * lightingMul + (lightingAdd * lightingAlpha), lightingAlpha);\n"
228 " fragColor.a = lightingAlpha;\n",
Romain Guyac670c02010-07-27 17:39:27 -0700229 // PorterDuff
230 " fragColor = blendColors(colorBlend, fragColor);\n"
231};
232const char* gFS_Footer =
233 "}\n\n";
234
235///////////////////////////////////////////////////////////////////////////////
236// PorterDuff snippets
237///////////////////////////////////////////////////////////////////////////////
238
Romain Guy48daa542010-08-10 19:21:34 -0700239const char* gBlendOps[18] = {
Romain Guyac670c02010-07-27 17:39:27 -0700240 // Clear
241 "return vec4(0.0, 0.0, 0.0, 0.0);\n",
242 // Src
243 "return src;\n",
244 // Dst
245 "return dst;\n",
246 // SrcOver
Romain Guy06f96e22010-07-30 19:18:16 -0700247 "return src + dst * (1.0 - src.a);\n",
Romain Guyac670c02010-07-27 17:39:27 -0700248 // DstOver
Romain Guy06f96e22010-07-30 19:18:16 -0700249 "return dst + src * (1.0 - dst.a);\n",
Romain Guyac670c02010-07-27 17:39:27 -0700250 // SrcIn
Romain Guy06f96e22010-07-30 19:18:16 -0700251 "return src * dst.a;\n",
Romain Guyac670c02010-07-27 17:39:27 -0700252 // DstIn
Romain Guy06f96e22010-07-30 19:18:16 -0700253 "return dst * src.a;\n",
Romain Guyac670c02010-07-27 17:39:27 -0700254 // SrcOut
Romain Guy06f96e22010-07-30 19:18:16 -0700255 "return src * (1.0 - dst.a);\n",
Romain Guyac670c02010-07-27 17:39:27 -0700256 // DstOut
Romain Guy06f96e22010-07-30 19:18:16 -0700257 "return dst * (1.0 - src.a);\n",
Romain Guyac670c02010-07-27 17:39:27 -0700258 // SrcAtop
259 "return vec4(src.rgb * dst.a + (1.0 - src.a) * dst.rgb, dst.a);\n",
260 // DstAtop
261 "return vec4(dst.rgb * src.a + (1.0 - dst.a) * src.rgb, src.a);\n",
262 // Xor
Romain Guy48daa542010-08-10 19:21:34 -0700263 "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb, "
Romain Guyac670c02010-07-27 17:39:27 -0700264 "src.a + dst.a - 2.0 * src.a * dst.a);\n",
Romain Guy48daa542010-08-10 19:21:34 -0700265 // Add
266 "return min(src + dst, 1.0);\n",
267 // Multiply
268 "return src * dst;\n",
269 // Screen
270 "return src + dst - src * dst;\n",
271 // Overlay
272 "return clamp(vec4(mix("
273 "2.0 * src.rgb * dst.rgb + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), "
274 "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), "
275 "step(dst.a, 2.0 * dst.rgb)), "
276 "src.a + dst.a - src.a * dst.a), 0.0, 1.0);\n",
277 // Darken
278 "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + "
279 "min(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n",
280 // Lighten
281 "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + "
282 "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 -0700283};
284
285///////////////////////////////////////////////////////////////////////////////
286// Constructors/destructors
287///////////////////////////////////////////////////////////////////////////////
288
289ProgramCache::ProgramCache() {
290}
291
292ProgramCache::~ProgramCache() {
293 clear();
294}
295
296///////////////////////////////////////////////////////////////////////////////
297// Cache management
298///////////////////////////////////////////////////////////////////////////////
299
300void ProgramCache::clear() {
Romain Guy67f27952010-12-07 20:09:23 -0800301 PROGRAM_LOGD("Clearing program cache");
302
Romain Guyac670c02010-07-27 17:39:27 -0700303 size_t count = mCache.size();
304 for (size_t i = 0; i < count; i++) {
305 delete mCache.valueAt(i);
306 }
307 mCache.clear();
308}
309
310Program* ProgramCache::get(const ProgramDescription& description) {
311 programid key = description.key();
312 ssize_t index = mCache.indexOfKey(key);
313 Program* program = NULL;
314 if (index < 0) {
Romain Guyee916f12010-09-20 17:53:08 -0700315 description.log("Could not find program");
Romain Guyac670c02010-07-27 17:39:27 -0700316 program = generateProgram(description, key);
317 mCache.add(key, program);
318 } else {
319 program = mCache.valueAt(index);
320 }
321 return program;
322}
323
324///////////////////////////////////////////////////////////////////////////////
325// Program generation
326///////////////////////////////////////////////////////////////////////////////
327
328Program* ProgramCache::generateProgram(const ProgramDescription& description, programid key) {
329 String8 vertexShader = generateVertexShader(description);
330 String8 fragmentShader = generateFragmentShader(description);
331
332 Program* program = new Program(vertexShader.string(), fragmentShader.string());
333 return program;
334}
335
336String8 ProgramCache::generateVertexShader(const ProgramDescription& description) {
337 // Add attributes
338 String8 shader(gVS_Header_Attributes);
Romain Guy889f8d12010-07-29 14:37:42 -0700339 if (description.hasTexture) {
Romain Guyac670c02010-07-27 17:39:27 -0700340 shader.append(gVS_Header_Attributes_TexCoords);
341 }
342 // Uniforms
343 shader.append(gVS_Header_Uniforms);
344 if (description.hasGradient) {
Romain Guyee916f12010-09-20 17:53:08 -0700345 shader.append(gVS_Header_Uniforms_HasGradient[description.gradientType]);
Romain Guyac670c02010-07-27 17:39:27 -0700346 }
Romain Guy889f8d12010-07-29 14:37:42 -0700347 if (description.hasBitmap) {
348 shader.append(gVS_Header_Uniforms_HasBitmap);
349 }
Romain Guyac670c02010-07-27 17:39:27 -0700350 // Varyings
351 if (description.hasTexture) {
352 shader.append(gVS_Header_Varyings_HasTexture);
353 }
354 if (description.hasGradient) {
Romain Guyee916f12010-09-20 17:53:08 -0700355 shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]);
Romain Guyac670c02010-07-27 17:39:27 -0700356 }
357 if (description.hasBitmap) {
358 shader.append(gVS_Header_Varyings_HasBitmap);
359 }
360
361 // Begin the shader
362 shader.append(gVS_Main); {
363 if (description.hasTexture) {
364 shader.append(gVS_Main_OutTexCoords);
365 }
366 if (description.hasGradient) {
Romain Guyee916f12010-09-20 17:53:08 -0700367 shader.append(gVS_Main_OutGradient[description.gradientType]);
Romain Guyac670c02010-07-27 17:39:27 -0700368 }
Romain Guy889f8d12010-07-29 14:37:42 -0700369 if (description.hasBitmap) {
370 shader.append(gVS_Main_OutBitmapTexCoords);
371 }
Romain Guyac670c02010-07-27 17:39:27 -0700372 // Output transformed position
373 shader.append(gVS_Main_Position);
374 }
375 // End the shader
376 shader.append(gVS_Footer);
377
378 PROGRAM_LOGD("*** Generated vertex shader:\n\n%s", shader.string());
379
380 return shader;
381}
382
383String8 ProgramCache::generateFragmentShader(const ProgramDescription& description) {
384 // Set the default precision
Romain Guya5aed0d2010-09-09 14:42:43 -0700385 String8 shader;
386
Romain Guy707b2f72010-10-11 16:34:59 -0700387 const bool blendFramebuffer = description.framebufferMode >= SkXfermode::kPlus_Mode;
Romain Guya5aed0d2010-09-09 14:42:43 -0700388 if (blendFramebuffer) {
389 shader.append(gFS_Header_Extension_FramebufferFetch);
390 }
391
392 shader.append(gFS_Header);
Romain Guyac670c02010-07-27 17:39:27 -0700393
394 // Varyings
395 if (description.hasTexture) {
396 shader.append(gVS_Header_Varyings_HasTexture);
397 }
398 if (description.hasGradient) {
Romain Guyee916f12010-09-20 17:53:08 -0700399 shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]);
Romain Guyac670c02010-07-27 17:39:27 -0700400 }
401 if (description.hasBitmap) {
402 shader.append(gVS_Header_Varyings_HasBitmap);
403 }
404
Romain Guyac670c02010-07-27 17:39:27 -0700405 // Uniforms
Romain Guy707b2f72010-10-11 16:34:59 -0700406 int modulateOp = MODULATE_OP_NO_MODULATE;
407 const bool singleColor = !description.hasTexture &&
408 !description.hasGradient && !description.hasBitmap;
409
410 if (description.modulate || singleColor) {
411 shader.append(gFS_Uniforms_Color);
412 if (!singleColor) modulateOp = MODULATE_OP_MODULATE;
413 }
Romain Guyac670c02010-07-27 17:39:27 -0700414 if (description.hasTexture) {
415 shader.append(gFS_Uniforms_TextureSampler);
416 }
417 if (description.hasGradient) {
Romain Guyee916f12010-09-20 17:53:08 -0700418 shader.append(gFS_Uniforms_GradientSampler[description.gradientType]);
Romain Guyac670c02010-07-27 17:39:27 -0700419 }
Romain Guy707b2f72010-10-11 16:34:59 -0700420
421 // Optimization for common cases
Romain Guy4afdf662010-10-13 21:31:28 -0700422 if (!blendFramebuffer && description.colorOp == ProgramDescription::kColorNone) {
Romain Guy707b2f72010-10-11 16:34:59 -0700423 bool fast = false;
424
425 const bool noShader = !description.hasGradient && !description.hasBitmap;
426 const bool singleTexture = description.hasTexture &&
427 !description.hasAlpha8Texture && noShader;
428 const bool singleA8Texture = description.hasTexture &&
429 description.hasAlpha8Texture && noShader;
430 const bool singleGradient = !description.hasTexture &&
431 description.hasGradient && !description.hasBitmap &&
432 description.gradientType == ProgramDescription::kGradientLinear;
433
434 if (singleColor) {
435 shader.append(gFS_Fast_SingleColor);
436 fast = true;
437 } else if (singleTexture) {
438 if (!description.modulate) {
439 shader.append(gFS_Fast_SingleTexture);
440 } else {
441 shader.append(gFS_Fast_SingleModulateTexture);
442 }
443 fast = true;
444 } else if (singleA8Texture) {
445 if (!description.modulate) {
446 shader.append(gFS_Fast_SingleA8Texture);
447 } else {
448 shader.append(gFS_Fast_SingleModulateA8Texture);
449 }
450 fast = true;
451 } else if (singleGradient) {
452 if (!description.modulate) {
453 shader.append(gFS_Fast_SingleGradient);
454 } else {
455 shader.append(gFS_Fast_SingleModulateGradient);
456 }
457 fast = true;
458 }
459
460 if (fast) {
Romain Guyc15008e2010-11-10 11:59:15 -0800461#if DEBUG_PROGRAMS
Romain Guy707b2f72010-10-11 16:34:59 -0700462 PROGRAM_LOGD("*** Fast case:\n");
463 PROGRAM_LOGD("*** Generated fragment shader:\n\n");
464 printLongString(shader);
Romain Guyc15008e2010-11-10 11:59:15 -0800465#endif
Romain Guy707b2f72010-10-11 16:34:59 -0700466
467 return shader;
468 }
469 }
470
Romain Guyac670c02010-07-27 17:39:27 -0700471 if (description.hasBitmap) {
472 shader.append(gFS_Uniforms_BitmapSampler);
473 }
474 shader.append(gFS_Uniforms_ColorOp[description.colorOp]);
475
476 // Generate required functions
477 if (description.hasGradient && description.hasBitmap) {
Romain Guy48daa542010-08-10 19:21:34 -0700478 generateBlend(shader, "blendShaders", description.shadersMode);
Romain Guyac670c02010-07-27 17:39:27 -0700479 }
480 if (description.colorOp == ProgramDescription::kColorBlend) {
Romain Guy48daa542010-08-10 19:21:34 -0700481 generateBlend(shader, "blendColors", description.colorMode);
Romain Guyac670c02010-07-27 17:39:27 -0700482 }
Romain Guya5aed0d2010-09-09 14:42:43 -0700483 if (blendFramebuffer) {
484 generateBlend(shader, "blendFramebuffer", description.framebufferMode);
485 }
Romain Guy889f8d12010-07-29 14:37:42 -0700486 if (description.isBitmapNpot) {
487 generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT);
488 }
Romain Guyac670c02010-07-27 17:39:27 -0700489
490 // Begin the shader
491 shader.append(gFS_Main); {
492 // Stores the result in fragColor directly
493 if (description.hasTexture) {
494 if (description.hasAlpha8Texture) {
Romain Guy707b2f72010-10-11 16:34:59 -0700495 if (!description.hasGradient && !description.hasBitmap) {
496 shader.append(gFS_Main_FetchA8Texture[modulateOp]);
497 }
Romain Guyac670c02010-07-27 17:39:27 -0700498 } else {
Romain Guy707b2f72010-10-11 16:34:59 -0700499 shader.append(gFS_Main_FetchTexture[modulateOp]);
Romain Guyac670c02010-07-27 17:39:27 -0700500 }
501 } else {
Romain Guy707b2f72010-10-11 16:34:59 -0700502 if ((!description.hasGradient && !description.hasBitmap) || description.modulate) {
503 shader.append(gFS_Main_FetchColor);
504 }
Romain Guyac670c02010-07-27 17:39:27 -0700505 }
506 if (description.hasGradient) {
Romain Guyee916f12010-09-20 17:53:08 -0700507 shader.append(gFS_Main_FetchGradient[description.gradientType]);
Romain Guyac670c02010-07-27 17:39:27 -0700508 }
509 if (description.hasBitmap) {
Romain Guy889f8d12010-07-29 14:37:42 -0700510 if (!description.isBitmapNpot) {
511 shader.append(gFS_Main_FetchBitmap);
512 } else {
513 shader.append(gFS_Main_FetchBitmapNpot);
514 }
Romain Guyac670c02010-07-27 17:39:27 -0700515 }
516 // Case when we have two shaders set
517 if (description.hasGradient && description.hasBitmap) {
Romain Guy707b2f72010-10-11 16:34:59 -0700518 int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp;
Romain Guyac670c02010-07-27 17:39:27 -0700519 if (description.isBitmapFirst) {
520 shader.append(gFS_Main_BlendShadersBG);
521 } else {
522 shader.append(gFS_Main_BlendShadersGB);
523 }
Romain Guy707b2f72010-10-11 16:34:59 -0700524 shader.append(gFS_Main_BlendShaders_Modulate[op]);
Romain Guy889f8d12010-07-29 14:37:42 -0700525 } else {
526 if (description.hasGradient) {
Romain Guy707b2f72010-10-11 16:34:59 -0700527 int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp;
528 shader.append(gFS_Main_GradientShader_Modulate[op]);
Romain Guy889f8d12010-07-29 14:37:42 -0700529 } else if (description.hasBitmap) {
Romain Guy707b2f72010-10-11 16:34:59 -0700530 int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp;
531 shader.append(gFS_Main_BitmapShader_Modulate[op]);
Romain Guy889f8d12010-07-29 14:37:42 -0700532 }
Romain Guyac670c02010-07-27 17:39:27 -0700533 }
534 // Apply the color op if needed
535 shader.append(gFS_Main_ApplyColorOp[description.colorOp]);
536 // Output the fragment
Romain Guya5aed0d2010-09-09 14:42:43 -0700537 if (!blendFramebuffer) {
538 shader.append(gFS_Main_FragColor);
539 } else {
Romain Guyf607bdc2010-09-10 19:20:06 -0700540 shader.append(!description.swapSrcDst ?
541 gFS_Main_FragColor_Blend : gFS_Main_FragColor_Blend_Swap);
Romain Guya5aed0d2010-09-09 14:42:43 -0700542 }
Romain Guyac670c02010-07-27 17:39:27 -0700543 }
544 // End the shader
545 shader.append(gFS_Footer);
546
Romain Guyc15008e2010-11-10 11:59:15 -0800547#if DEBUG_PROGRAMS
Romain Guydb1938e2010-08-02 18:50:22 -0700548 PROGRAM_LOGD("*** Generated fragment shader:\n\n");
549 printLongString(shader);
Romain Guyc15008e2010-11-10 11:59:15 -0800550#endif
Romain Guydb1938e2010-08-02 18:50:22 -0700551
Romain Guyac670c02010-07-27 17:39:27 -0700552 return shader;
553}
554
Romain Guy48daa542010-08-10 19:21:34 -0700555void ProgramCache::generateBlend(String8& shader, const char* name, SkXfermode::Mode mode) {
Romain Guyac670c02010-07-27 17:39:27 -0700556 shader.append("\nvec4 ");
557 shader.append(name);
558 shader.append("(vec4 src, vec4 dst) {\n");
559 shader.append(" ");
Romain Guy48daa542010-08-10 19:21:34 -0700560 shader.append(gBlendOps[mode]);
Romain Guyac670c02010-07-27 17:39:27 -0700561 shader.append("}\n");
562}
563
Romain Guy889f8d12010-07-29 14:37:42 -0700564void ProgramCache::generateTextureWrap(String8& shader, GLenum wrapS, GLenum wrapT) {
565 shader.append("\nvec2 wrap(vec2 texCoords) {\n");
566 if (wrapS == GL_MIRRORED_REPEAT) {
567 shader.append(" float xMod2 = mod(texCoords.x, 2.0);\n");
568 shader.append(" if (xMod2 > 1.0) xMod2 = 2.0 - xMod2;\n");
569 }
570 if (wrapT == GL_MIRRORED_REPEAT) {
571 shader.append(" float yMod2 = mod(texCoords.y, 2.0);\n");
572 shader.append(" if (yMod2 > 1.0) yMod2 = 2.0 - yMod2;\n");
573 }
574 shader.append(" return vec2(");
575 switch (wrapS) {
Romain Guy61c8c9c2010-08-09 20:48:09 -0700576 case GL_CLAMP_TO_EDGE:
577 shader.append("texCoords.x");
578 break;
Romain Guy889f8d12010-07-29 14:37:42 -0700579 case GL_REPEAT:
580 shader.append("mod(texCoords.x, 1.0)");
581 break;
582 case GL_MIRRORED_REPEAT:
583 shader.append("xMod2");
584 break;
585 }
586 shader.append(", ");
587 switch (wrapT) {
Romain Guy61c8c9c2010-08-09 20:48:09 -0700588 case GL_CLAMP_TO_EDGE:
589 shader.append("texCoords.y");
590 break;
Romain Guy889f8d12010-07-29 14:37:42 -0700591 case GL_REPEAT:
592 shader.append("mod(texCoords.y, 1.0)");
593 break;
594 case GL_MIRRORED_REPEAT:
595 shader.append("yMod2");
596 break;
597 }
598 shader.append(");\n");
599 shader.append("}\n");
600}
601
Romain Guydb1938e2010-08-02 18:50:22 -0700602void ProgramCache::printLongString(const String8& shader) const {
603 ssize_t index = 0;
604 ssize_t lastIndex = 0;
605 const char* str = shader.string();
606 while ((index = shader.find("\n", index)) > -1) {
607 String8 line(str, index - lastIndex);
608 if (line.length() == 0) line.append("\n");
609 PROGRAM_LOGD("%s", line.string());
610 index++;
611 str += (index - lastIndex);
612 lastIndex = index;
613 }
614}
615
Romain Guyac670c02010-07-27 17:39:27 -0700616}; // namespace uirenderer
617}; // namespace android