blob: 1282b7102788c6524943cf979358ccde5002adac [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"
139 " gl_FragColor = vec4(0.0, 0.0, 0.0, texture2D(sampler, outTexCoords).a);\n"
140 "}\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
165 " fragColor = vec4(0.0, 0.0, 0.0, texture2D(sampler, outTexCoords).a);\n",
166 // 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() {
301 size_t count = mCache.size();
302 for (size_t i = 0; i < count; i++) {
303 delete mCache.valueAt(i);
304 }
305 mCache.clear();
306}
307
308Program* ProgramCache::get(const ProgramDescription& description) {
309 programid key = description.key();
310 ssize_t index = mCache.indexOfKey(key);
311 Program* program = NULL;
312 if (index < 0) {
Romain Guyee916f12010-09-20 17:53:08 -0700313 description.log("Could not find program");
Romain Guyac670c02010-07-27 17:39:27 -0700314 program = generateProgram(description, key);
315 mCache.add(key, program);
316 } else {
317 program = mCache.valueAt(index);
318 }
319 return program;
320}
321
322///////////////////////////////////////////////////////////////////////////////
323// Program generation
324///////////////////////////////////////////////////////////////////////////////
325
326Program* ProgramCache::generateProgram(const ProgramDescription& description, programid key) {
327 String8 vertexShader = generateVertexShader(description);
328 String8 fragmentShader = generateFragmentShader(description);
329
330 Program* program = new Program(vertexShader.string(), fragmentShader.string());
331 return program;
332}
333
334String8 ProgramCache::generateVertexShader(const ProgramDescription& description) {
335 // Add attributes
336 String8 shader(gVS_Header_Attributes);
Romain Guy889f8d12010-07-29 14:37:42 -0700337 if (description.hasTexture) {
Romain Guyac670c02010-07-27 17:39:27 -0700338 shader.append(gVS_Header_Attributes_TexCoords);
339 }
340 // Uniforms
341 shader.append(gVS_Header_Uniforms);
342 if (description.hasGradient) {
Romain Guyee916f12010-09-20 17:53:08 -0700343 shader.append(gVS_Header_Uniforms_HasGradient[description.gradientType]);
Romain Guyac670c02010-07-27 17:39:27 -0700344 }
Romain Guy889f8d12010-07-29 14:37:42 -0700345 if (description.hasBitmap) {
346 shader.append(gVS_Header_Uniforms_HasBitmap);
347 }
Romain Guyac670c02010-07-27 17:39:27 -0700348 // Varyings
349 if (description.hasTexture) {
350 shader.append(gVS_Header_Varyings_HasTexture);
351 }
352 if (description.hasGradient) {
Romain Guyee916f12010-09-20 17:53:08 -0700353 shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]);
Romain Guyac670c02010-07-27 17:39:27 -0700354 }
355 if (description.hasBitmap) {
356 shader.append(gVS_Header_Varyings_HasBitmap);
357 }
358
359 // Begin the shader
360 shader.append(gVS_Main); {
361 if (description.hasTexture) {
362 shader.append(gVS_Main_OutTexCoords);
363 }
364 if (description.hasGradient) {
Romain Guyee916f12010-09-20 17:53:08 -0700365 shader.append(gVS_Main_OutGradient[description.gradientType]);
Romain Guyac670c02010-07-27 17:39:27 -0700366 }
Romain Guy889f8d12010-07-29 14:37:42 -0700367 if (description.hasBitmap) {
368 shader.append(gVS_Main_OutBitmapTexCoords);
369 }
Romain Guyac670c02010-07-27 17:39:27 -0700370 // Output transformed position
371 shader.append(gVS_Main_Position);
372 }
373 // End the shader
374 shader.append(gVS_Footer);
375
376 PROGRAM_LOGD("*** Generated vertex shader:\n\n%s", shader.string());
377
378 return shader;
379}
380
381String8 ProgramCache::generateFragmentShader(const ProgramDescription& description) {
382 // Set the default precision
Romain Guya5aed0d2010-09-09 14:42:43 -0700383 String8 shader;
384
Romain Guy707b2f72010-10-11 16:34:59 -0700385 const bool blendFramebuffer = description.framebufferMode >= SkXfermode::kPlus_Mode;
Romain Guya5aed0d2010-09-09 14:42:43 -0700386 if (blendFramebuffer) {
387 shader.append(gFS_Header_Extension_FramebufferFetch);
388 }
389
390 shader.append(gFS_Header);
Romain Guyac670c02010-07-27 17:39:27 -0700391
392 // Varyings
393 if (description.hasTexture) {
394 shader.append(gVS_Header_Varyings_HasTexture);
395 }
396 if (description.hasGradient) {
Romain Guyee916f12010-09-20 17:53:08 -0700397 shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]);
Romain Guyac670c02010-07-27 17:39:27 -0700398 }
399 if (description.hasBitmap) {
400 shader.append(gVS_Header_Varyings_HasBitmap);
401 }
402
Romain Guyac670c02010-07-27 17:39:27 -0700403 // Uniforms
Romain Guy707b2f72010-10-11 16:34:59 -0700404 int modulateOp = MODULATE_OP_NO_MODULATE;
405 const bool singleColor = !description.hasTexture &&
406 !description.hasGradient && !description.hasBitmap;
407
408 if (description.modulate || singleColor) {
409 shader.append(gFS_Uniforms_Color);
410 if (!singleColor) modulateOp = MODULATE_OP_MODULATE;
411 }
Romain Guyac670c02010-07-27 17:39:27 -0700412 if (description.hasTexture) {
413 shader.append(gFS_Uniforms_TextureSampler);
414 }
415 if (description.hasGradient) {
Romain Guyee916f12010-09-20 17:53:08 -0700416 shader.append(gFS_Uniforms_GradientSampler[description.gradientType]);
Romain Guyac670c02010-07-27 17:39:27 -0700417 }
Romain Guy707b2f72010-10-11 16:34:59 -0700418
419 // Optimization for common cases
420 if (!blendFramebuffer) {
421 bool fast = false;
422
423 const bool noShader = !description.hasGradient && !description.hasBitmap;
424 const bool singleTexture = description.hasTexture &&
425 !description.hasAlpha8Texture && noShader;
426 const bool singleA8Texture = description.hasTexture &&
427 description.hasAlpha8Texture && noShader;
428 const bool singleGradient = !description.hasTexture &&
429 description.hasGradient && !description.hasBitmap &&
430 description.gradientType == ProgramDescription::kGradientLinear;
431
432 if (singleColor) {
433 shader.append(gFS_Fast_SingleColor);
434 fast = true;
435 } else if (singleTexture) {
436 if (!description.modulate) {
437 shader.append(gFS_Fast_SingleTexture);
438 } else {
439 shader.append(gFS_Fast_SingleModulateTexture);
440 }
441 fast = true;
442 } else if (singleA8Texture) {
443 if (!description.modulate) {
444 shader.append(gFS_Fast_SingleA8Texture);
445 } else {
446 shader.append(gFS_Fast_SingleModulateA8Texture);
447 }
448 fast = true;
449 } else if (singleGradient) {
450 if (!description.modulate) {
451 shader.append(gFS_Fast_SingleGradient);
452 } else {
453 shader.append(gFS_Fast_SingleModulateGradient);
454 }
455 fast = true;
456 }
457
458 if (fast) {
459 if (DEBUG_PROGRAM_CACHE) {
460 PROGRAM_LOGD("*** Fast case:\n");
461 PROGRAM_LOGD("*** Generated fragment shader:\n\n");
462 printLongString(shader);
463 }
464
465 return shader;
466 }
467 }
468
Romain Guyac670c02010-07-27 17:39:27 -0700469 if (description.hasBitmap) {
470 shader.append(gFS_Uniforms_BitmapSampler);
471 }
472 shader.append(gFS_Uniforms_ColorOp[description.colorOp]);
473
474 // Generate required functions
475 if (description.hasGradient && description.hasBitmap) {
Romain Guy48daa542010-08-10 19:21:34 -0700476 generateBlend(shader, "blendShaders", description.shadersMode);
Romain Guyac670c02010-07-27 17:39:27 -0700477 }
478 if (description.colorOp == ProgramDescription::kColorBlend) {
Romain Guy48daa542010-08-10 19:21:34 -0700479 generateBlend(shader, "blendColors", description.colorMode);
Romain Guyac670c02010-07-27 17:39:27 -0700480 }
Romain Guya5aed0d2010-09-09 14:42:43 -0700481 if (blendFramebuffer) {
482 generateBlend(shader, "blendFramebuffer", description.framebufferMode);
483 }
Romain Guy889f8d12010-07-29 14:37:42 -0700484 if (description.isBitmapNpot) {
485 generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT);
486 }
Romain Guyac670c02010-07-27 17:39:27 -0700487
488 // Begin the shader
489 shader.append(gFS_Main); {
490 // Stores the result in fragColor directly
491 if (description.hasTexture) {
492 if (description.hasAlpha8Texture) {
Romain Guy707b2f72010-10-11 16:34:59 -0700493 if (!description.hasGradient && !description.hasBitmap) {
494 shader.append(gFS_Main_FetchA8Texture[modulateOp]);
495 }
Romain Guyac670c02010-07-27 17:39:27 -0700496 } else {
Romain Guy707b2f72010-10-11 16:34:59 -0700497 shader.append(gFS_Main_FetchTexture[modulateOp]);
Romain Guyac670c02010-07-27 17:39:27 -0700498 }
499 } else {
Romain Guy707b2f72010-10-11 16:34:59 -0700500 if ((!description.hasGradient && !description.hasBitmap) || description.modulate) {
501 shader.append(gFS_Main_FetchColor);
502 }
Romain Guyac670c02010-07-27 17:39:27 -0700503 }
504 if (description.hasGradient) {
Romain Guyee916f12010-09-20 17:53:08 -0700505 shader.append(gFS_Main_FetchGradient[description.gradientType]);
Romain Guyac670c02010-07-27 17:39:27 -0700506 }
507 if (description.hasBitmap) {
Romain Guy889f8d12010-07-29 14:37:42 -0700508 if (!description.isBitmapNpot) {
509 shader.append(gFS_Main_FetchBitmap);
510 } else {
511 shader.append(gFS_Main_FetchBitmapNpot);
512 }
Romain Guyac670c02010-07-27 17:39:27 -0700513 }
514 // Case when we have two shaders set
515 if (description.hasGradient && description.hasBitmap) {
Romain Guy707b2f72010-10-11 16:34:59 -0700516 int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp;
Romain Guyac670c02010-07-27 17:39:27 -0700517 if (description.isBitmapFirst) {
518 shader.append(gFS_Main_BlendShadersBG);
519 } else {
520 shader.append(gFS_Main_BlendShadersGB);
521 }
Romain Guy707b2f72010-10-11 16:34:59 -0700522 shader.append(gFS_Main_BlendShaders_Modulate[op]);
Romain Guy889f8d12010-07-29 14:37:42 -0700523 } else {
524 if (description.hasGradient) {
Romain Guy707b2f72010-10-11 16:34:59 -0700525 int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp;
526 shader.append(gFS_Main_GradientShader_Modulate[op]);
Romain Guy889f8d12010-07-29 14:37:42 -0700527 } else if (description.hasBitmap) {
Romain Guy707b2f72010-10-11 16:34:59 -0700528 int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp;
529 shader.append(gFS_Main_BitmapShader_Modulate[op]);
Romain Guy889f8d12010-07-29 14:37:42 -0700530 }
Romain Guyac670c02010-07-27 17:39:27 -0700531 }
532 // Apply the color op if needed
533 shader.append(gFS_Main_ApplyColorOp[description.colorOp]);
534 // Output the fragment
Romain Guya5aed0d2010-09-09 14:42:43 -0700535 if (!blendFramebuffer) {
536 shader.append(gFS_Main_FragColor);
537 } else {
Romain Guyf607bdc2010-09-10 19:20:06 -0700538 shader.append(!description.swapSrcDst ?
539 gFS_Main_FragColor_Blend : gFS_Main_FragColor_Blend_Swap);
Romain Guya5aed0d2010-09-09 14:42:43 -0700540 }
Romain Guyac670c02010-07-27 17:39:27 -0700541 }
542 // End the shader
543 shader.append(gFS_Footer);
544
Romain Guydb1938e2010-08-02 18:50:22 -0700545 if (DEBUG_PROGRAM_CACHE) {
546 PROGRAM_LOGD("*** Generated fragment shader:\n\n");
547 printLongString(shader);
548 }
549
Romain Guyac670c02010-07-27 17:39:27 -0700550 return shader;
551}
552
Romain Guy48daa542010-08-10 19:21:34 -0700553void ProgramCache::generateBlend(String8& shader, const char* name, SkXfermode::Mode mode) {
Romain Guyac670c02010-07-27 17:39:27 -0700554 shader.append("\nvec4 ");
555 shader.append(name);
556 shader.append("(vec4 src, vec4 dst) {\n");
557 shader.append(" ");
Romain Guy48daa542010-08-10 19:21:34 -0700558 shader.append(gBlendOps[mode]);
Romain Guyac670c02010-07-27 17:39:27 -0700559 shader.append("}\n");
560}
561
Romain Guy889f8d12010-07-29 14:37:42 -0700562void ProgramCache::generateTextureWrap(String8& shader, GLenum wrapS, GLenum wrapT) {
563 shader.append("\nvec2 wrap(vec2 texCoords) {\n");
564 if (wrapS == GL_MIRRORED_REPEAT) {
565 shader.append(" float xMod2 = mod(texCoords.x, 2.0);\n");
566 shader.append(" if (xMod2 > 1.0) xMod2 = 2.0 - xMod2;\n");
567 }
568 if (wrapT == GL_MIRRORED_REPEAT) {
569 shader.append(" float yMod2 = mod(texCoords.y, 2.0);\n");
570 shader.append(" if (yMod2 > 1.0) yMod2 = 2.0 - yMod2;\n");
571 }
572 shader.append(" return vec2(");
573 switch (wrapS) {
Romain Guy61c8c9c2010-08-09 20:48:09 -0700574 case GL_CLAMP_TO_EDGE:
575 shader.append("texCoords.x");
576 break;
Romain Guy889f8d12010-07-29 14:37:42 -0700577 case GL_REPEAT:
578 shader.append("mod(texCoords.x, 1.0)");
579 break;
580 case GL_MIRRORED_REPEAT:
581 shader.append("xMod2");
582 break;
583 }
584 shader.append(", ");
585 switch (wrapT) {
Romain Guy61c8c9c2010-08-09 20:48:09 -0700586 case GL_CLAMP_TO_EDGE:
587 shader.append("texCoords.y");
588 break;
Romain Guy889f8d12010-07-29 14:37:42 -0700589 case GL_REPEAT:
590 shader.append("mod(texCoords.y, 1.0)");
591 break;
592 case GL_MIRRORED_REPEAT:
593 shader.append("yMod2");
594 break;
595 }
596 shader.append(");\n");
597 shader.append("}\n");
598}
599
Romain Guydb1938e2010-08-02 18:50:22 -0700600void ProgramCache::printLongString(const String8& shader) const {
601 ssize_t index = 0;
602 ssize_t lastIndex = 0;
603 const char* str = shader.string();
604 while ((index = shader.find("\n", index)) > -1) {
605 String8 line(str, index - lastIndex);
606 if (line.length() == 0) line.append("\n");
607 PROGRAM_LOGD("%s", line.string());
608 index++;
609 str += (index - lastIndex);
610 lastIndex = index;
611 }
612}
613
Romain Guyac670c02010-07-27 17:39:27 -0700614}; // namespace uirenderer
615}; // namespace android