blob: c2383f4c7256d50b74c291cea03f45fb9ca41873 [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
Romain Guya60c3882011-08-01 15:28:16 -070021#include "Caches.h"
Romain Guyac670c02010-07-27 17:39:27 -070022#include "ProgramCache.h"
23
24namespace android {
25namespace uirenderer {
26
27///////////////////////////////////////////////////////////////////////////////
Romain Guy707b2f72010-10-11 16:34:59 -070028// Defines
29///////////////////////////////////////////////////////////////////////////////
30
31#define MODULATE_OP_NO_MODULATE 0
32#define MODULATE_OP_MODULATE 1
33#define MODULATE_OP_MODULATE_A8 2
34
35///////////////////////////////////////////////////////////////////////////////
Romain Guyac670c02010-07-27 17:39:27 -070036// Vertex shaders snippets
37///////////////////////////////////////////////////////////////////////////////
38
Romain Guyac670c02010-07-27 17:39:27 -070039const char* gVS_Header_Attributes =
40 "attribute vec4 position;\n";
41const char* gVS_Header_Attributes_TexCoords =
42 "attribute vec2 texCoords;\n";
Chet Haase99585ad2011-05-02 15:00:16 -070043const char* gVS_Header_Attributes_AAParameters =
44 "attribute float vtxWidth;\n"
45 "attribute float vtxLength;\n";
Romain Guyaa6c24c2011-04-28 18:40:04 -070046const char* gVS_Header_Uniforms_TextureTransform =
47 "uniform mat4 mainTextureTransform;\n";
Romain Guyac670c02010-07-27 17:39:27 -070048const char* gVS_Header_Uniforms =
49 "uniform mat4 transform;\n";
Romain Guyed6fcb02011-03-21 13:11:28 -070050const char* gVS_Header_Uniforms_IsPoint =
Romain Guy80bbfb12011-03-23 16:56:28 -070051 "uniform mediump float pointSize;\n";
Romain Guyee916f12010-09-20 17:53:08 -070052const char* gVS_Header_Uniforms_HasGradient[3] = {
53 // Linear
Romain Guyee916f12010-09-20 17:53:08 -070054 "uniform mat4 screenSpace;\n",
55 // Circular
Romain Guyddb80be2010-09-20 19:04:33 -070056 "uniform mat4 screenSpace;\n",
Romain Guyee916f12010-09-20 17:53:08 -070057 // Sweep
Romain Guyee916f12010-09-20 17:53:08 -070058 "uniform mat4 screenSpace;\n"
59};
Romain Guy889f8d12010-07-29 14:37:42 -070060const char* gVS_Header_Uniforms_HasBitmap =
61 "uniform mat4 textureTransform;\n"
Romain Guy80bbfb12011-03-23 16:56:28 -070062 "uniform mediump vec2 textureDimension;\n";
Romain Guyac670c02010-07-27 17:39:27 -070063const char* gVS_Header_Varyings_HasTexture =
64 "varying vec2 outTexCoords;\n";
Chet Haase99585ad2011-05-02 15:00:16 -070065const char* gVS_Header_Varyings_IsAA =
66 "varying float widthProportion;\n"
67 "varying float lengthProportion;\n";
Romain Guya60c3882011-08-01 15:28:16 -070068const char* gVS_Header_Varyings_HasBitmap[2] = {
69 // Default precision
70 "varying vec2 outBitmapTexCoords;\n",
71 // High precision
72 "varying highp vec2 outBitmapTexCoords;\n"
73};
74const char* gVS_Header_Varyings_PointHasBitmap[2] = {
75 // Default precision
76 "varying vec2 outPointBitmapTexCoords;\n",
77 // High precision
78 "varying highp vec2 outPointBitmapTexCoords;\n"
79};
Romain Guyee916f12010-09-20 17:53:08 -070080const char* gVS_Header_Varyings_HasGradient[3] = {
81 // Linear
Romain Guy7537f852010-10-11 14:38:28 -070082 "varying vec2 linear;\n",
Romain Guyee916f12010-09-20 17:53:08 -070083 // Circular
Romain Guyddb80be2010-09-20 19:04:33 -070084 "varying vec2 circular;\n",
Romain Guyee916f12010-09-20 17:53:08 -070085 // Sweep
86 "varying vec2 sweep;\n"
87};
Romain Guyac670c02010-07-27 17:39:27 -070088const char* gVS_Main =
89 "\nvoid main(void) {\n";
90const char* gVS_Main_OutTexCoords =
91 " outTexCoords = texCoords;\n";
Romain Guyaa6c24c2011-04-28 18:40:04 -070092const char* gVS_Main_OutTransformedTexCoords =
93 " outTexCoords = (mainTextureTransform * vec4(texCoords, 0.0, 1.0)).xy;\n";
Romain Guyee916f12010-09-20 17:53:08 -070094const char* gVS_Main_OutGradient[3] = {
95 // Linear
Romain Guy7537f852010-10-11 14:38:28 -070096 " linear = vec2((screenSpace * position).x, 0.5);\n",
Romain Guyee916f12010-09-20 17:53:08 -070097 // Circular
Romain Guy14830942010-10-07 15:07:45 -070098 " circular = (screenSpace * position).xy;\n",
Romain Guyee916f12010-09-20 17:53:08 -070099 // Sweep
Romain Guy14830942010-10-07 15:07:45 -0700100 " sweep = (screenSpace * position).xy;\n"
Romain Guyee916f12010-09-20 17:53:08 -0700101};
Romain Guy889f8d12010-07-29 14:37:42 -0700102const char* gVS_Main_OutBitmapTexCoords =
Romain Guy707b2f72010-10-11 16:34:59 -0700103 " outBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n";
Romain Guyed6fcb02011-03-21 13:11:28 -0700104const char* gVS_Main_OutPointBitmapTexCoords =
105 " outPointBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n";
Romain Guyac670c02010-07-27 17:39:27 -0700106const char* gVS_Main_Position =
107 " gl_Position = transform * position;\n";
Romain Guyed6fcb02011-03-21 13:11:28 -0700108const char* gVS_Main_PointSize =
109 " gl_PointSize = pointSize;\n";
Chet Haase99585ad2011-05-02 15:00:16 -0700110const char* gVS_Main_AA =
111 " widthProportion = vtxWidth;\n"
112 " lengthProportion = vtxLength;\n";
Romain Guyac670c02010-07-27 17:39:27 -0700113const char* gVS_Footer =
114 "}\n\n";
115
116///////////////////////////////////////////////////////////////////////////////
117// Fragment shaders snippets
118///////////////////////////////////////////////////////////////////////////////
119
Romain Guya5aed0d2010-09-09 14:42:43 -0700120const char* gFS_Header_Extension_FramebufferFetch =
121 "#extension GL_NV_shader_framebuffer_fetch : enable\n\n";
Romain Guyaa6c24c2011-04-28 18:40:04 -0700122const char* gFS_Header_Extension_ExternalTexture =
123 "#extension GL_OES_EGL_image_external : require\n\n";
Romain Guyac670c02010-07-27 17:39:27 -0700124const char* gFS_Header =
125 "precision mediump float;\n\n";
126const char* gFS_Uniforms_Color =
127 "uniform vec4 color;\n";
Chet Haase99585ad2011-05-02 15:00:16 -0700128const char* gFS_Uniforms_AA =
Chet Haase5b0200b2011-04-13 17:58:08 -0700129 "uniform float boundaryWidth;\n"
Chet Haase99585ad2011-05-02 15:00:16 -0700130 "uniform float inverseBoundaryWidth;\n"
131 "uniform float boundaryLength;\n"
132 "uniform float inverseBoundaryLength;\n";
Romain Guyed6fcb02011-03-21 13:11:28 -0700133const char* gFS_Header_Uniforms_PointHasBitmap =
134 "uniform vec2 textureDimension;\n"
135 "uniform float pointSize;\n";
Romain Guyac670c02010-07-27 17:39:27 -0700136const char* gFS_Uniforms_TextureSampler =
137 "uniform sampler2D sampler;\n";
Romain Guyaa6c24c2011-04-28 18:40:04 -0700138const char* gFS_Uniforms_ExternalTextureSampler =
139 "uniform samplerExternalOES sampler;\n";
Romain Guyee916f12010-09-20 17:53:08 -0700140const char* gFS_Uniforms_GradientSampler[3] = {
141 // Linear
142 "uniform sampler2D gradientSampler;\n",
143 // Circular
144 "uniform sampler2D gradientSampler;\n",
145 // Sweep
146 "uniform sampler2D gradientSampler;\n"
147};
Romain Guyac670c02010-07-27 17:39:27 -0700148const char* gFS_Uniforms_BitmapSampler =
149 "uniform sampler2D bitmapSampler;\n";
150const char* gFS_Uniforms_ColorOp[4] = {
151 // None
152 "",
153 // Matrix
154 "uniform mat4 colorMatrix;\n"
155 "uniform vec4 colorMatrixVector;\n",
156 // Lighting
Romain Guydb1938e2010-08-02 18:50:22 -0700157 "uniform vec4 lightingMul;\n"
158 "uniform vec4 lightingAdd;\n",
Romain Guyac670c02010-07-27 17:39:27 -0700159 // PorterDuff
Romain Guydb1938e2010-08-02 18:50:22 -0700160 "uniform vec4 colorBlend;\n"
Romain Guyac670c02010-07-27 17:39:27 -0700161};
162const char* gFS_Main =
163 "\nvoid main(void) {\n"
Romain Guy7fbcc042010-08-04 15:40:07 -0700164 " lowp vec4 fragColor;\n";
Romain Guy707b2f72010-10-11 16:34:59 -0700165
Romain Guyed6fcb02011-03-21 13:11:28 -0700166const char* gFS_Main_PointBitmapTexCoords =
167 " vec2 outBitmapTexCoords = outPointBitmapTexCoords + "
168 "((gl_PointCoord - vec2(0.5, 0.5)) * textureDimension * vec2(pointSize, pointSize));\n";
169
Romain Guy707b2f72010-10-11 16:34:59 -0700170// Fast cases
171const char* gFS_Fast_SingleColor =
172 "\nvoid main(void) {\n"
173 " gl_FragColor = color;\n"
174 "}\n\n";
175const char* gFS_Fast_SingleTexture =
176 "\nvoid main(void) {\n"
177 " gl_FragColor = texture2D(sampler, outTexCoords);\n"
178 "}\n\n";
179const char* gFS_Fast_SingleModulateTexture =
180 "\nvoid main(void) {\n"
181 " gl_FragColor = color.a * texture2D(sampler, outTexCoords);\n"
182 "}\n\n";
183const char* gFS_Fast_SingleA8Texture =
184 "\nvoid main(void) {\n"
Romain Guy9db91242010-10-12 13:13:09 -0700185 " gl_FragColor = texture2D(sampler, outTexCoords);\n"
Romain Guy707b2f72010-10-11 16:34:59 -0700186 "}\n\n";
187const char* gFS_Fast_SingleModulateA8Texture =
188 "\nvoid main(void) {\n"
189 " gl_FragColor = color * texture2D(sampler, outTexCoords).a;\n"
190 "}\n\n";
191const char* gFS_Fast_SingleGradient =
192 "\nvoid main(void) {\n"
193 " gl_FragColor = texture2D(gradientSampler, linear);\n"
194 "}\n\n";
195const char* gFS_Fast_SingleModulateGradient =
196 "\nvoid main(void) {\n"
197 " gl_FragColor = color.a * texture2D(gradientSampler, linear);\n"
198 "}\n\n";
199
200// General case
Romain Guyac670c02010-07-27 17:39:27 -0700201const char* gFS_Main_FetchColor =
202 " fragColor = color;\n";
Romain Guy740bf2b2011-04-26 15:33:10 -0700203const char* gFS_Main_ModulateColor =
204 " fragColor *= color.a;\n";
Chet Haase99585ad2011-05-02 15:00:16 -0700205const char* gFS_Main_AccountForAA =
206 " if (widthProportion < boundaryWidth) {\n"
207 " fragColor *= (widthProportion * inverseBoundaryWidth);\n"
208 " } else if (widthProportion > (1.0 - boundaryWidth)) {\n"
209 " fragColor *= ((1.0 - widthProportion) * inverseBoundaryWidth);\n"
210 " }\n"
211 " if (lengthProportion < boundaryLength) {\n"
212 " fragColor *= (lengthProportion * inverseBoundaryLength);\n"
213 " } else if (lengthProportion > (1.0 - boundaryLength)) {\n"
214 " fragColor *= ((1.0 - lengthProportion) * inverseBoundaryLength);\n"
Chet Haase5b0200b2011-04-13 17:58:08 -0700215 " }\n";
Romain Guy707b2f72010-10-11 16:34:59 -0700216const char* gFS_Main_FetchTexture[2] = {
217 // Don't modulate
218 " fragColor = texture2D(sampler, outTexCoords);\n",
219 // Modulate
220 " fragColor = color * texture2D(sampler, outTexCoords);\n"
221};
222const char* gFS_Main_FetchA8Texture[2] = {
223 // Don't modulate
Romain Guy9db91242010-10-12 13:13:09 -0700224 " fragColor = texture2D(sampler, outTexCoords);\n",
Romain Guy707b2f72010-10-11 16:34:59 -0700225 // Modulate
226 " fragColor = color * texture2D(sampler, outTexCoords).a;\n"
227};
Romain Guyee916f12010-09-20 17:53:08 -0700228const char* gFS_Main_FetchGradient[3] = {
229 // Linear
Romain Guy7537f852010-10-11 14:38:28 -0700230 " vec4 gradientColor = texture2D(gradientSampler, linear);\n",
Romain Guyee916f12010-09-20 17:53:08 -0700231 // Circular
Romain Guy14830942010-10-07 15:07:45 -0700232 " float index = length(circular);\n"
Romain Guyddb80be2010-09-20 19:04:33 -0700233 " vec4 gradientColor = texture2D(gradientSampler, vec2(index, 0.5));\n",
Romain Guyee916f12010-09-20 17:53:08 -0700234 // Sweep
235 " float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
236 " vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n"
237};
Romain Guyac670c02010-07-27 17:39:27 -0700238const char* gFS_Main_FetchBitmap =
239 " vec4 bitmapColor = texture2D(bitmapSampler, outBitmapTexCoords);\n";
Romain Guy889f8d12010-07-29 14:37:42 -0700240const char* gFS_Main_FetchBitmapNpot =
241 " vec4 bitmapColor = texture2D(bitmapSampler, wrap(outBitmapTexCoords));\n";
Romain Guyac670c02010-07-27 17:39:27 -0700242const char* gFS_Main_BlendShadersBG =
Romain Guyac670c02010-07-27 17:39:27 -0700243 " fragColor = blendShaders(gradientColor, bitmapColor)";
Romain Guy06f96e22010-07-30 19:18:16 -0700244const char* gFS_Main_BlendShadersGB =
245 " fragColor = blendShaders(bitmapColor, gradientColor)";
Romain Guy707b2f72010-10-11 16:34:59 -0700246const char* gFS_Main_BlendShaders_Modulate[3] = {
247 // Don't modulate
248 ";\n",
249 // Modulate
250 " * fragColor.a;\n",
251 // Modulate with alpha 8 texture
252 " * texture2D(sampler, outTexCoords).a;\n"
253};
254const char* gFS_Main_GradientShader_Modulate[3] = {
255 // Don't modulate
256 " fragColor = gradientColor;\n",
257 // Modulate
258 " fragColor = gradientColor * fragColor.a;\n",
259 // Modulate with alpha 8 texture
260 " fragColor = gradientColor * texture2D(sampler, outTexCoords).a;\n"
261 };
262const char* gFS_Main_BitmapShader_Modulate[3] = {
263 // Don't modulate
264 " fragColor = bitmapColor;\n",
265 // Modulate
266 " fragColor = bitmapColor * fragColor.a;\n",
267 // Modulate with alpha 8 texture
268 " fragColor = bitmapColor * texture2D(sampler, outTexCoords).a;\n"
269 };
Romain Guyac670c02010-07-27 17:39:27 -0700270const char* gFS_Main_FragColor =
271 " gl_FragColor = fragColor;\n";
Romain Guya5aed0d2010-09-09 14:42:43 -0700272const char* gFS_Main_FragColor_Blend =
273 " gl_FragColor = blendFramebuffer(fragColor, gl_LastFragColor);\n";
Romain Guyf607bdc2010-09-10 19:20:06 -0700274const char* gFS_Main_FragColor_Blend_Swap =
275 " gl_FragColor = blendFramebuffer(gl_LastFragColor, fragColor);\n";
Romain Guyac670c02010-07-27 17:39:27 -0700276const char* gFS_Main_ApplyColorOp[4] = {
277 // None
278 "",
279 // Matrix
Romain Guydb1938e2010-08-02 18:50:22 -0700280 // TODO: Fix premultiplied alpha computations for color matrix
Romain Guyac670c02010-07-27 17:39:27 -0700281 " fragColor *= colorMatrix;\n"
Romain Guydb1938e2010-08-02 18:50:22 -0700282 " fragColor += colorMatrixVector;\n"
283 " fragColor.rgb *= fragColor.a;\n",
Romain Guyac670c02010-07-27 17:39:27 -0700284 // Lighting
Romain Guydb1938e2010-08-02 18:50:22 -0700285 " float lightingAlpha = fragColor.a;\n"
286 " fragColor = min(fragColor * lightingMul + (lightingAdd * lightingAlpha), lightingAlpha);\n"
287 " fragColor.a = lightingAlpha;\n",
Romain Guyac670c02010-07-27 17:39:27 -0700288 // PorterDuff
289 " fragColor = blendColors(colorBlend, fragColor);\n"
290};
291const char* gFS_Footer =
292 "}\n\n";
293
294///////////////////////////////////////////////////////////////////////////////
295// PorterDuff snippets
296///////////////////////////////////////////////////////////////////////////////
297
Romain Guy48daa542010-08-10 19:21:34 -0700298const char* gBlendOps[18] = {
Romain Guyac670c02010-07-27 17:39:27 -0700299 // Clear
300 "return vec4(0.0, 0.0, 0.0, 0.0);\n",
301 // Src
302 "return src;\n",
303 // Dst
304 "return dst;\n",
305 // SrcOver
Romain Guy06f96e22010-07-30 19:18:16 -0700306 "return src + dst * (1.0 - src.a);\n",
Romain Guyac670c02010-07-27 17:39:27 -0700307 // DstOver
Romain Guy06f96e22010-07-30 19:18:16 -0700308 "return dst + src * (1.0 - dst.a);\n",
Romain Guyac670c02010-07-27 17:39:27 -0700309 // SrcIn
Romain Guy06f96e22010-07-30 19:18:16 -0700310 "return src * dst.a;\n",
Romain Guyac670c02010-07-27 17:39:27 -0700311 // DstIn
Romain Guy06f96e22010-07-30 19:18:16 -0700312 "return dst * src.a;\n",
Romain Guyac670c02010-07-27 17:39:27 -0700313 // SrcOut
Romain Guy06f96e22010-07-30 19:18:16 -0700314 "return src * (1.0 - dst.a);\n",
Romain Guyac670c02010-07-27 17:39:27 -0700315 // DstOut
Romain Guy06f96e22010-07-30 19:18:16 -0700316 "return dst * (1.0 - src.a);\n",
Romain Guyac670c02010-07-27 17:39:27 -0700317 // SrcAtop
318 "return vec4(src.rgb * dst.a + (1.0 - src.a) * dst.rgb, dst.a);\n",
319 // DstAtop
320 "return vec4(dst.rgb * src.a + (1.0 - dst.a) * src.rgb, src.a);\n",
321 // Xor
Romain Guy48daa542010-08-10 19:21:34 -0700322 "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb, "
Romain Guyac670c02010-07-27 17:39:27 -0700323 "src.a + dst.a - 2.0 * src.a * dst.a);\n",
Romain Guy48daa542010-08-10 19:21:34 -0700324 // Add
325 "return min(src + dst, 1.0);\n",
326 // Multiply
327 "return src * dst;\n",
328 // Screen
329 "return src + dst - src * dst;\n",
330 // Overlay
331 "return clamp(vec4(mix("
332 "2.0 * src.rgb * dst.rgb + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), "
333 "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), "
334 "step(dst.a, 2.0 * dst.rgb)), "
335 "src.a + dst.a - src.a * dst.a), 0.0, 1.0);\n",
336 // Darken
337 "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + "
338 "min(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n",
339 // Lighten
340 "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + "
341 "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 -0700342};
343
344///////////////////////////////////////////////////////////////////////////////
345// Constructors/destructors
346///////////////////////////////////////////////////////////////////////////////
347
348ProgramCache::ProgramCache() {
349}
350
351ProgramCache::~ProgramCache() {
352 clear();
353}
354
355///////////////////////////////////////////////////////////////////////////////
356// Cache management
357///////////////////////////////////////////////////////////////////////////////
358
359void ProgramCache::clear() {
Romain Guy67f27952010-12-07 20:09:23 -0800360 PROGRAM_LOGD("Clearing program cache");
361
Romain Guyac670c02010-07-27 17:39:27 -0700362 size_t count = mCache.size();
363 for (size_t i = 0; i < count; i++) {
364 delete mCache.valueAt(i);
365 }
366 mCache.clear();
367}
368
369Program* ProgramCache::get(const ProgramDescription& description) {
370 programid key = description.key();
371 ssize_t index = mCache.indexOfKey(key);
372 Program* program = NULL;
373 if (index < 0) {
Romain Guyee916f12010-09-20 17:53:08 -0700374 description.log("Could not find program");
Romain Guyac670c02010-07-27 17:39:27 -0700375 program = generateProgram(description, key);
376 mCache.add(key, program);
377 } else {
378 program = mCache.valueAt(index);
379 }
380 return program;
381}
382
383///////////////////////////////////////////////////////////////////////////////
384// Program generation
385///////////////////////////////////////////////////////////////////////////////
386
387Program* ProgramCache::generateProgram(const ProgramDescription& description, programid key) {
388 String8 vertexShader = generateVertexShader(description);
389 String8 fragmentShader = generateFragmentShader(description);
390
391 Program* program = new Program(vertexShader.string(), fragmentShader.string());
392 return program;
393}
394
395String8 ProgramCache::generateVertexShader(const ProgramDescription& description) {
396 // Add attributes
397 String8 shader(gVS_Header_Attributes);
Romain Guyaa6c24c2011-04-28 18:40:04 -0700398 if (description.hasTexture || description.hasExternalTexture) {
Romain Guyac670c02010-07-27 17:39:27 -0700399 shader.append(gVS_Header_Attributes_TexCoords);
400 }
Chet Haase99585ad2011-05-02 15:00:16 -0700401 if (description.isAA) {
402 shader.append(gVS_Header_Attributes_AAParameters);
Chet Haase5b0200b2011-04-13 17:58:08 -0700403 }
Romain Guyac670c02010-07-27 17:39:27 -0700404 // Uniforms
405 shader.append(gVS_Header_Uniforms);
Romain Guy8f0095c2011-05-02 17:24:22 -0700406 if (description.hasTextureTransform) {
Romain Guyaa6c24c2011-04-28 18:40:04 -0700407 shader.append(gVS_Header_Uniforms_TextureTransform);
408 }
Romain Guyac670c02010-07-27 17:39:27 -0700409 if (description.hasGradient) {
Romain Guyee916f12010-09-20 17:53:08 -0700410 shader.append(gVS_Header_Uniforms_HasGradient[description.gradientType]);
Romain Guyac670c02010-07-27 17:39:27 -0700411 }
Romain Guy889f8d12010-07-29 14:37:42 -0700412 if (description.hasBitmap) {
413 shader.append(gVS_Header_Uniforms_HasBitmap);
414 }
Romain Guyed6fcb02011-03-21 13:11:28 -0700415 if (description.isPoint) {
416 shader.append(gVS_Header_Uniforms_IsPoint);
417 }
Romain Guyac670c02010-07-27 17:39:27 -0700418 // Varyings
Romain Guyaa6c24c2011-04-28 18:40:04 -0700419 if (description.hasTexture || description.hasExternalTexture) {
Romain Guyac670c02010-07-27 17:39:27 -0700420 shader.append(gVS_Header_Varyings_HasTexture);
421 }
Chet Haase99585ad2011-05-02 15:00:16 -0700422 if (description.isAA) {
423 shader.append(gVS_Header_Varyings_IsAA);
Chet Haase5b0200b2011-04-13 17:58:08 -0700424 }
Romain Guyac670c02010-07-27 17:39:27 -0700425 if (description.hasGradient) {
Romain Guyee916f12010-09-20 17:53:08 -0700426 shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]);
Romain Guyac670c02010-07-27 17:39:27 -0700427 }
428 if (description.hasBitmap) {
Romain Guya60c3882011-08-01 15:28:16 -0700429 int index = Caches::getInstance().extensions.needsHighpTexCoords() ? 1 : 0;
Romain Guyed6fcb02011-03-21 13:11:28 -0700430 shader.append(description.isPoint ?
Romain Guya60c3882011-08-01 15:28:16 -0700431 gVS_Header_Varyings_PointHasBitmap[index] :
432 gVS_Header_Varyings_HasBitmap[index]);
Romain Guyac670c02010-07-27 17:39:27 -0700433 }
434
435 // Begin the shader
436 shader.append(gVS_Main); {
Romain Guy8f0095c2011-05-02 17:24:22 -0700437 if (description.hasTextureTransform) {
Romain Guyaa6c24c2011-04-28 18:40:04 -0700438 shader.append(gVS_Main_OutTransformedTexCoords);
Romain Guy8f0095c2011-05-02 17:24:22 -0700439 } else if (description.hasTexture || description.hasExternalTexture) {
440 shader.append(gVS_Main_OutTexCoords);
Romain Guyaa6c24c2011-04-28 18:40:04 -0700441 }
Chet Haase99585ad2011-05-02 15:00:16 -0700442 if (description.isAA) {
443 shader.append(gVS_Main_AA);
Chet Haase5b0200b2011-04-13 17:58:08 -0700444 }
Romain Guyac670c02010-07-27 17:39:27 -0700445 if (description.hasGradient) {
Romain Guyee916f12010-09-20 17:53:08 -0700446 shader.append(gVS_Main_OutGradient[description.gradientType]);
Romain Guyac670c02010-07-27 17:39:27 -0700447 }
Romain Guy889f8d12010-07-29 14:37:42 -0700448 if (description.hasBitmap) {
Romain Guyed6fcb02011-03-21 13:11:28 -0700449 shader.append(description.isPoint ?
450 gVS_Main_OutPointBitmapTexCoords :
451 gVS_Main_OutBitmapTexCoords);
452 }
453 if (description.isPoint) {
454 shader.append(gVS_Main_PointSize);
Romain Guy889f8d12010-07-29 14:37:42 -0700455 }
Romain Guyac670c02010-07-27 17:39:27 -0700456 // Output transformed position
457 shader.append(gVS_Main_Position);
458 }
459 // End the shader
460 shader.append(gVS_Footer);
461
462 PROGRAM_LOGD("*** Generated vertex shader:\n\n%s", shader.string());
463
464 return shader;
465}
466
467String8 ProgramCache::generateFragmentShader(const ProgramDescription& description) {
Romain Guya5aed0d2010-09-09 14:42:43 -0700468 String8 shader;
469
Romain Guy707b2f72010-10-11 16:34:59 -0700470 const bool blendFramebuffer = description.framebufferMode >= SkXfermode::kPlus_Mode;
Romain Guya5aed0d2010-09-09 14:42:43 -0700471 if (blendFramebuffer) {
472 shader.append(gFS_Header_Extension_FramebufferFetch);
473 }
Romain Guyaa6c24c2011-04-28 18:40:04 -0700474 if (description.hasExternalTexture) {
475 shader.append(gFS_Header_Extension_ExternalTexture);
476 }
Romain Guya5aed0d2010-09-09 14:42:43 -0700477
478 shader.append(gFS_Header);
Romain Guyac670c02010-07-27 17:39:27 -0700479
480 // Varyings
Romain Guyaa6c24c2011-04-28 18:40:04 -0700481 if (description.hasTexture || description.hasExternalTexture) {
Romain Guyac670c02010-07-27 17:39:27 -0700482 shader.append(gVS_Header_Varyings_HasTexture);
483 }
Chet Haase99585ad2011-05-02 15:00:16 -0700484 if (description.isAA) {
485 shader.append(gVS_Header_Varyings_IsAA);
Chet Haase5b0200b2011-04-13 17:58:08 -0700486 }
Romain Guyac670c02010-07-27 17:39:27 -0700487 if (description.hasGradient) {
Romain Guyee916f12010-09-20 17:53:08 -0700488 shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]);
Romain Guyac670c02010-07-27 17:39:27 -0700489 }
490 if (description.hasBitmap) {
Romain Guya60c3882011-08-01 15:28:16 -0700491 int index = Caches::getInstance().extensions.needsHighpTexCoords() ? 1 : 0;
Romain Guyed6fcb02011-03-21 13:11:28 -0700492 shader.append(description.isPoint ?
Romain Guya60c3882011-08-01 15:28:16 -0700493 gVS_Header_Varyings_PointHasBitmap[index] :
494 gVS_Header_Varyings_HasBitmap[index]);
Romain Guyac670c02010-07-27 17:39:27 -0700495 }
496
Romain Guyac670c02010-07-27 17:39:27 -0700497 // Uniforms
Romain Guy707b2f72010-10-11 16:34:59 -0700498 int modulateOp = MODULATE_OP_NO_MODULATE;
Romain Guyaa6c24c2011-04-28 18:40:04 -0700499 const bool singleColor = !description.hasTexture && !description.hasExternalTexture &&
Romain Guy707b2f72010-10-11 16:34:59 -0700500 !description.hasGradient && !description.hasBitmap;
501
502 if (description.modulate || singleColor) {
503 shader.append(gFS_Uniforms_Color);
504 if (!singleColor) modulateOp = MODULATE_OP_MODULATE;
505 }
Romain Guyac670c02010-07-27 17:39:27 -0700506 if (description.hasTexture) {
507 shader.append(gFS_Uniforms_TextureSampler);
Romain Guy8f0095c2011-05-02 17:24:22 -0700508 } else if (description.hasExternalTexture) {
Romain Guyaa6c24c2011-04-28 18:40:04 -0700509 shader.append(gFS_Uniforms_ExternalTextureSampler);
510 }
Chet Haase99585ad2011-05-02 15:00:16 -0700511 if (description.isAA) {
512 shader.append(gFS_Uniforms_AA);
Chet Haase5b0200b2011-04-13 17:58:08 -0700513 }
Romain Guyac670c02010-07-27 17:39:27 -0700514 if (description.hasGradient) {
Romain Guyee916f12010-09-20 17:53:08 -0700515 shader.append(gFS_Uniforms_GradientSampler[description.gradientType]);
Romain Guyac670c02010-07-27 17:39:27 -0700516 }
Romain Guyed6fcb02011-03-21 13:11:28 -0700517 if (description.hasBitmap && description.isPoint) {
518 shader.append(gFS_Header_Uniforms_PointHasBitmap);
519 }
Romain Guy707b2f72010-10-11 16:34:59 -0700520
521 // Optimization for common cases
Chet Haase99585ad2011-05-02 15:00:16 -0700522 if (!description.isAA && !blendFramebuffer &&
Chet Haase5b0200b2011-04-13 17:58:08 -0700523 description.colorOp == ProgramDescription::kColorNone && !description.isPoint) {
Romain Guy707b2f72010-10-11 16:34:59 -0700524 bool fast = false;
525
526 const bool noShader = !description.hasGradient && !description.hasBitmap;
Romain Guyaa6c24c2011-04-28 18:40:04 -0700527 const bool singleTexture = (description.hasTexture || description.hasExternalTexture) &&
Romain Guy707b2f72010-10-11 16:34:59 -0700528 !description.hasAlpha8Texture && noShader;
529 const bool singleA8Texture = description.hasTexture &&
530 description.hasAlpha8Texture && noShader;
Romain Guyaa6c24c2011-04-28 18:40:04 -0700531 const bool singleGradient = !description.hasTexture && !description.hasExternalTexture &&
Romain Guy707b2f72010-10-11 16:34:59 -0700532 description.hasGradient && !description.hasBitmap &&
533 description.gradientType == ProgramDescription::kGradientLinear;
534
535 if (singleColor) {
536 shader.append(gFS_Fast_SingleColor);
537 fast = true;
538 } else if (singleTexture) {
539 if (!description.modulate) {
540 shader.append(gFS_Fast_SingleTexture);
541 } else {
542 shader.append(gFS_Fast_SingleModulateTexture);
543 }
544 fast = true;
545 } else if (singleA8Texture) {
546 if (!description.modulate) {
547 shader.append(gFS_Fast_SingleA8Texture);
548 } else {
549 shader.append(gFS_Fast_SingleModulateA8Texture);
550 }
551 fast = true;
552 } else if (singleGradient) {
553 if (!description.modulate) {
554 shader.append(gFS_Fast_SingleGradient);
555 } else {
556 shader.append(gFS_Fast_SingleModulateGradient);
557 }
558 fast = true;
559 }
560
561 if (fast) {
Romain Guyc15008e2010-11-10 11:59:15 -0800562#if DEBUG_PROGRAMS
Romain Guy707b2f72010-10-11 16:34:59 -0700563 PROGRAM_LOGD("*** Fast case:\n");
564 PROGRAM_LOGD("*** Generated fragment shader:\n\n");
565 printLongString(shader);
Romain Guyc15008e2010-11-10 11:59:15 -0800566#endif
Romain Guy707b2f72010-10-11 16:34:59 -0700567
568 return shader;
569 }
570 }
571
Romain Guyac670c02010-07-27 17:39:27 -0700572 if (description.hasBitmap) {
573 shader.append(gFS_Uniforms_BitmapSampler);
574 }
575 shader.append(gFS_Uniforms_ColorOp[description.colorOp]);
576
577 // Generate required functions
578 if (description.hasGradient && description.hasBitmap) {
Romain Guy48daa542010-08-10 19:21:34 -0700579 generateBlend(shader, "blendShaders", description.shadersMode);
Romain Guyac670c02010-07-27 17:39:27 -0700580 }
581 if (description.colorOp == ProgramDescription::kColorBlend) {
Romain Guy48daa542010-08-10 19:21:34 -0700582 generateBlend(shader, "blendColors", description.colorMode);
Romain Guyac670c02010-07-27 17:39:27 -0700583 }
Romain Guya5aed0d2010-09-09 14:42:43 -0700584 if (blendFramebuffer) {
585 generateBlend(shader, "blendFramebuffer", description.framebufferMode);
586 }
Romain Guy889f8d12010-07-29 14:37:42 -0700587 if (description.isBitmapNpot) {
588 generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT);
589 }
Romain Guyac670c02010-07-27 17:39:27 -0700590
591 // Begin the shader
592 shader.append(gFS_Main); {
593 // Stores the result in fragColor directly
Romain Guyaa6c24c2011-04-28 18:40:04 -0700594 if (description.hasTexture || description.hasExternalTexture) {
Romain Guyac670c02010-07-27 17:39:27 -0700595 if (description.hasAlpha8Texture) {
Romain Guy707b2f72010-10-11 16:34:59 -0700596 if (!description.hasGradient && !description.hasBitmap) {
597 shader.append(gFS_Main_FetchA8Texture[modulateOp]);
598 }
Romain Guyac670c02010-07-27 17:39:27 -0700599 } else {
Romain Guy707b2f72010-10-11 16:34:59 -0700600 shader.append(gFS_Main_FetchTexture[modulateOp]);
Romain Guyac670c02010-07-27 17:39:27 -0700601 }
602 } else {
Romain Guy707b2f72010-10-11 16:34:59 -0700603 if ((!description.hasGradient && !description.hasBitmap) || description.modulate) {
604 shader.append(gFS_Main_FetchColor);
605 }
Romain Guyac670c02010-07-27 17:39:27 -0700606 }
Chet Haase99585ad2011-05-02 15:00:16 -0700607 if (description.isAA) {
608 shader.append(gFS_Main_AccountForAA);
Chet Haase5b0200b2011-04-13 17:58:08 -0700609 }
Romain Guyac670c02010-07-27 17:39:27 -0700610 if (description.hasGradient) {
Romain Guyee916f12010-09-20 17:53:08 -0700611 shader.append(gFS_Main_FetchGradient[description.gradientType]);
Romain Guyac670c02010-07-27 17:39:27 -0700612 }
613 if (description.hasBitmap) {
Romain Guyed6fcb02011-03-21 13:11:28 -0700614 if (description.isPoint) {
615 shader.append(gFS_Main_PointBitmapTexCoords);
616 }
Romain Guy889f8d12010-07-29 14:37:42 -0700617 if (!description.isBitmapNpot) {
618 shader.append(gFS_Main_FetchBitmap);
619 } else {
620 shader.append(gFS_Main_FetchBitmapNpot);
621 }
Romain Guyac670c02010-07-27 17:39:27 -0700622 }
Romain Guy740bf2b2011-04-26 15:33:10 -0700623 bool applyModulate = false;
Romain Guyac670c02010-07-27 17:39:27 -0700624 // Case when we have two shaders set
625 if (description.hasGradient && description.hasBitmap) {
Romain Guy707b2f72010-10-11 16:34:59 -0700626 int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp;
Romain Guyac670c02010-07-27 17:39:27 -0700627 if (description.isBitmapFirst) {
628 shader.append(gFS_Main_BlendShadersBG);
629 } else {
630 shader.append(gFS_Main_BlendShadersGB);
631 }
Romain Guy707b2f72010-10-11 16:34:59 -0700632 shader.append(gFS_Main_BlendShaders_Modulate[op]);
Romain Guy740bf2b2011-04-26 15:33:10 -0700633 applyModulate = true;
Romain Guy889f8d12010-07-29 14:37:42 -0700634 } else {
635 if (description.hasGradient) {
Romain Guy707b2f72010-10-11 16:34:59 -0700636 int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp;
637 shader.append(gFS_Main_GradientShader_Modulate[op]);
Romain Guy740bf2b2011-04-26 15:33:10 -0700638 applyModulate = true;
Romain Guy889f8d12010-07-29 14:37:42 -0700639 } else if (description.hasBitmap) {
Romain Guy707b2f72010-10-11 16:34:59 -0700640 int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp;
641 shader.append(gFS_Main_BitmapShader_Modulate[op]);
Romain Guy740bf2b2011-04-26 15:33:10 -0700642 applyModulate = true;
Romain Guy889f8d12010-07-29 14:37:42 -0700643 }
Romain Guyac670c02010-07-27 17:39:27 -0700644 }
Romain Guy740bf2b2011-04-26 15:33:10 -0700645 if (description.modulate && applyModulate) {
646 shader.append(gFS_Main_ModulateColor);
647 }
Romain Guyac670c02010-07-27 17:39:27 -0700648 // Apply the color op if needed
649 shader.append(gFS_Main_ApplyColorOp[description.colorOp]);
650 // Output the fragment
Romain Guya5aed0d2010-09-09 14:42:43 -0700651 if (!blendFramebuffer) {
652 shader.append(gFS_Main_FragColor);
653 } else {
Romain Guyf607bdc2010-09-10 19:20:06 -0700654 shader.append(!description.swapSrcDst ?
655 gFS_Main_FragColor_Blend : gFS_Main_FragColor_Blend_Swap);
Romain Guya5aed0d2010-09-09 14:42:43 -0700656 }
Romain Guyac670c02010-07-27 17:39:27 -0700657 }
658 // End the shader
659 shader.append(gFS_Footer);
660
Romain Guyc15008e2010-11-10 11:59:15 -0800661#if DEBUG_PROGRAMS
Romain Guydb1938e2010-08-02 18:50:22 -0700662 PROGRAM_LOGD("*** Generated fragment shader:\n\n");
663 printLongString(shader);
Romain Guyc15008e2010-11-10 11:59:15 -0800664#endif
Romain Guydb1938e2010-08-02 18:50:22 -0700665
Romain Guyac670c02010-07-27 17:39:27 -0700666 return shader;
667}
668
Romain Guy48daa542010-08-10 19:21:34 -0700669void ProgramCache::generateBlend(String8& shader, const char* name, SkXfermode::Mode mode) {
Romain Guyac670c02010-07-27 17:39:27 -0700670 shader.append("\nvec4 ");
671 shader.append(name);
672 shader.append("(vec4 src, vec4 dst) {\n");
673 shader.append(" ");
Romain Guy48daa542010-08-10 19:21:34 -0700674 shader.append(gBlendOps[mode]);
Romain Guyac670c02010-07-27 17:39:27 -0700675 shader.append("}\n");
676}
677
Romain Guy889f8d12010-07-29 14:37:42 -0700678void ProgramCache::generateTextureWrap(String8& shader, GLenum wrapS, GLenum wrapT) {
679 shader.append("\nvec2 wrap(vec2 texCoords) {\n");
680 if (wrapS == GL_MIRRORED_REPEAT) {
681 shader.append(" float xMod2 = mod(texCoords.x, 2.0);\n");
682 shader.append(" if (xMod2 > 1.0) xMod2 = 2.0 - xMod2;\n");
683 }
684 if (wrapT == GL_MIRRORED_REPEAT) {
685 shader.append(" float yMod2 = mod(texCoords.y, 2.0);\n");
686 shader.append(" if (yMod2 > 1.0) yMod2 = 2.0 - yMod2;\n");
687 }
688 shader.append(" return vec2(");
689 switch (wrapS) {
Romain Guy61c8c9c2010-08-09 20:48:09 -0700690 case GL_CLAMP_TO_EDGE:
691 shader.append("texCoords.x");
692 break;
Romain Guy889f8d12010-07-29 14:37:42 -0700693 case GL_REPEAT:
694 shader.append("mod(texCoords.x, 1.0)");
695 break;
696 case GL_MIRRORED_REPEAT:
697 shader.append("xMod2");
698 break;
699 }
700 shader.append(", ");
701 switch (wrapT) {
Romain Guy61c8c9c2010-08-09 20:48:09 -0700702 case GL_CLAMP_TO_EDGE:
703 shader.append("texCoords.y");
704 break;
Romain Guy889f8d12010-07-29 14:37:42 -0700705 case GL_REPEAT:
706 shader.append("mod(texCoords.y, 1.0)");
707 break;
708 case GL_MIRRORED_REPEAT:
709 shader.append("yMod2");
710 break;
711 }
712 shader.append(");\n");
713 shader.append("}\n");
714}
715
Romain Guydb1938e2010-08-02 18:50:22 -0700716void ProgramCache::printLongString(const String8& shader) const {
717 ssize_t index = 0;
718 ssize_t lastIndex = 0;
719 const char* str = shader.string();
720 while ((index = shader.find("\n", index)) > -1) {
721 String8 line(str, index - lastIndex);
722 if (line.length() == 0) line.append("\n");
723 PROGRAM_LOGD("%s", line.string());
724 index++;
725 str += (index - lastIndex);
726 lastIndex = index;
727 }
728}
729
Romain Guyac670c02010-07-27 17:39:27 -0700730}; // namespace uirenderer
731}; // namespace android