blob: 5a89eb6a3a1a66a7fbd02bebcbff14064303102c [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///////////////////////////////////////////////////////////////////////////////
27// Vertex shaders snippets
28///////////////////////////////////////////////////////////////////////////////
29
30// TODO: Implement BitmapShader, implement repeat/mirror for npot
31
32const char* gVS_Header_Attributes =
33 "attribute vec4 position;\n";
34const char* gVS_Header_Attributes_TexCoords =
35 "attribute vec2 texCoords;\n";
36const char* gVS_Header_Uniforms =
37 "uniform mat4 transform;\n";
38const char* gVS_Header_Uniforms_HasGradient =
39 "uniform float gradientLength;\n"
40 "uniform vec2 gradient;\n"
41 "uniform vec2 gradientStart;\n"
42 "uniform mat4 screenSpace;\n";
43const char* gVS_Header_Varyings_HasTexture =
44 "varying vec2 outTexCoords;\n";
45const char* gVS_Header_Varyings_HasBitmap =
46 "varying vec2 outBitmapTexCoords;\n";
47const char* gVS_Header_Varyings_HasGradient =
48 "varying float index;\n";
49const char* gVS_Main =
50 "\nvoid main(void) {\n";
51const char* gVS_Main_OutTexCoords =
52 " outTexCoords = texCoords;\n";
53const char* gVS_Main_OutGradientIndex =
54 " vec4 location = screenSpace * position;\n"
55 " index = dot(location.xy - gradientStart, gradient) * gradientLength;\n";
56const char* gVS_Main_Position =
57 " gl_Position = transform * position;\n";
58const char* gVS_Footer =
59 "}\n\n";
60
61///////////////////////////////////////////////////////////////////////////////
62// Fragment shaders snippets
63///////////////////////////////////////////////////////////////////////////////
64
65const char* gFS_Header =
66 "precision mediump float;\n\n";
67const char* gFS_Uniforms_Color =
68 "uniform vec4 color;\n";
69const char* gFS_Uniforms_TextureSampler =
70 "uniform sampler2D sampler;\n";
71const char* gFS_Uniforms_GradientSampler =
72 "uniform sampler2D gradientSampler;\n";
73const char* gFS_Uniforms_BitmapSampler =
74 "uniform sampler2D bitmapSampler;\n";
75const char* gFS_Uniforms_ColorOp[4] = {
76 // None
77 "",
78 // Matrix
79 "uniform mat4 colorMatrix;\n"
80 "uniform vec4 colorMatrixVector;\n",
81 // Lighting
82 "uniform float lightingMul;\n"
83 "uniform float lightingAdd;\n",
84 // PorterDuff
85 "uniform vec4 colorBLend;\n"
86};
87const char* gFS_Main =
88 "\nvoid main(void) {\n"
89 " vec4 fragColor;\n";
90const char* gFS_Main_FetchColor =
91 " fragColor = color;\n";
92const char* gFS_Main_FetchTexture =
93 " fragColor = color * texture2D(sampler, outTexCoords);\n";
94const char* gFS_Main_FetchA8Texture =
95 " fragColor = color * texture2D(sampler, outTexCoords).a;\n";
96const char* gFS_Main_FetchGradient =
97 " vec4 gradientColor = texture2D(gradientSampler, vec2(index, 0.5));\n";
98const char* gFS_Main_FetchBitmap =
99 " vec4 bitmapColor = texture2D(bitmapSampler, outBitmapTexCoords);\n";
100const char* gFS_Main_BlendShadersBG =
101 " fragColor = blendShaders(bitmapColor, gradientColor)";
102const char* gFS_Main_BlendShadersGB =
103 " fragColor = blendShaders(gradientColor, bitmapColor)";
104const char* gFS_Main_BlendShaders_Modulate =
105 " * fragColor.a;\n";
106const char* gFS_Main_FragColor =
107 " gl_FragColor = fragColor;\n";
108const char* gFS_Main_ApplyColorOp[4] = {
109 // None
110 "",
111 // Matrix
112 " fragColor *= colorMatrix;\n"
113 " fragColor += colorMatrixVector;\n",
114 // Lighting
115 " fragColor *= lightingMul;\n"
116 " fragColor += lightingAdd;\n",
117 // PorterDuff
118 " fragColor = blendColors(colorBlend, fragColor);\n"
119};
120const char* gFS_Footer =
121 "}\n\n";
122
123///////////////////////////////////////////////////////////////////////////////
124// PorterDuff snippets
125///////////////////////////////////////////////////////////////////////////////
126
127const char* gPorterDuff[12] = {
128 // Clear
129 "return vec4(0.0, 0.0, 0.0, 0.0);\n",
130 // Src
131 "return src;\n",
132 // Dst
133 "return dst;\n",
134 // SrcOver
135 "return vec4(src.rgb + (1.0 - src.a) * dst.rgb, src.a + dst.a - src.a * dst.a);\n",
136 // DstOver
137 "return vec4(dst.rgb + (1.0 - dst.a) * src.rgb, src.a + dst.a - src.a * dst.a);\n",
138 // SrcIn
139 "return vec4(src.rgb * dst.a, src.a * dst.a);\n",
140 // DstIn
141 "return vec4(dst.rgb * src.a, src.a * dst.a);\n",
142 // SrcOut
143 "return vec4(src.rgb * (1.0 - dst.a), src.a * (1.0 - dst.a));\n",
144 // DstOut
145 "return vec4(dst.rgb * (1.0 - src.a), dst.a * (1.0 - src.a));\n",
146 // SrcAtop
147 "return vec4(src.rgb * dst.a + (1.0 - src.a) * dst.rgb, dst.a);\n",
148 // DstAtop
149 "return vec4(dst.rgb * src.a + (1.0 - dst.a) * src.rgb, src.a);\n",
150 // Xor
151 "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb, "
152 "src.a + dst.a - 2.0 * src.a * dst.a);\n",
153};
154
155///////////////////////////////////////////////////////////////////////////////
156// Constructors/destructors
157///////////////////////////////////////////////////////////////////////////////
158
159ProgramCache::ProgramCache() {
160}
161
162ProgramCache::~ProgramCache() {
163 clear();
164}
165
166///////////////////////////////////////////////////////////////////////////////
167// Cache management
168///////////////////////////////////////////////////////////////////////////////
169
170void ProgramCache::clear() {
171 size_t count = mCache.size();
172 for (size_t i = 0; i < count; i++) {
173 delete mCache.valueAt(i);
174 }
175 mCache.clear();
176}
177
178Program* ProgramCache::get(const ProgramDescription& description) {
179 programid key = description.key();
180 ssize_t index = mCache.indexOfKey(key);
181 Program* program = NULL;
182 if (index < 0) {
183 PROGRAM_LOGD("Could not find program with key 0x%x", key);
184 program = generateProgram(description, key);
185 mCache.add(key, program);
186 } else {
187 program = mCache.valueAt(index);
188 }
189 return program;
190}
191
192///////////////////////////////////////////////////////////////////////////////
193// Program generation
194///////////////////////////////////////////////////////////////////////////////
195
196Program* ProgramCache::generateProgram(const ProgramDescription& description, programid key) {
197 String8 vertexShader = generateVertexShader(description);
198 String8 fragmentShader = generateFragmentShader(description);
199
200 Program* program = new Program(vertexShader.string(), fragmentShader.string());
201 return program;
202}
203
204String8 ProgramCache::generateVertexShader(const ProgramDescription& description) {
205 // Add attributes
206 String8 shader(gVS_Header_Attributes);
207 if (description.hasTexture || description.hasBitmap) {
208 shader.append(gVS_Header_Attributes_TexCoords);
209 }
210 // Uniforms
211 shader.append(gVS_Header_Uniforms);
212 if (description.hasGradient) {
213 shader.append(gVS_Header_Uniforms_HasGradient);
214 }
215 // Varyings
216 if (description.hasTexture) {
217 shader.append(gVS_Header_Varyings_HasTexture);
218 }
219 if (description.hasGradient) {
220 shader.append(gVS_Header_Varyings_HasGradient);
221 }
222 if (description.hasBitmap) {
223 shader.append(gVS_Header_Varyings_HasBitmap);
224 }
225
226 // Begin the shader
227 shader.append(gVS_Main); {
228 if (description.hasTexture) {
229 shader.append(gVS_Main_OutTexCoords);
230 }
231 if (description.hasGradient) {
232 shader.append(gVS_Main_OutGradientIndex);
233 }
234 // Output transformed position
235 shader.append(gVS_Main_Position);
236 }
237 // End the shader
238 shader.append(gVS_Footer);
239
240 PROGRAM_LOGD("*** Generated vertex shader:\n\n%s", shader.string());
241
242 return shader;
243}
244
245String8 ProgramCache::generateFragmentShader(const ProgramDescription& description) {
246 // Set the default precision
247 String8 shader(gFS_Header);
248
249 // Varyings
250 if (description.hasTexture) {
251 shader.append(gVS_Header_Varyings_HasTexture);
252 }
253 if (description.hasGradient) {
254 shader.append(gVS_Header_Varyings_HasGradient);
255 }
256 if (description.hasBitmap) {
257 shader.append(gVS_Header_Varyings_HasBitmap);
258 }
259
260
261 // Uniforms
262 shader.append(gFS_Uniforms_Color);
263 if (description.hasTexture) {
264 shader.append(gFS_Uniforms_TextureSampler);
265 }
266 if (description.hasGradient) {
267 shader.append(gFS_Uniforms_GradientSampler);
268 }
269 if (description.hasBitmap) {
270 shader.append(gFS_Uniforms_BitmapSampler);
271 }
272 shader.append(gFS_Uniforms_ColorOp[description.colorOp]);
273
274 // Generate required functions
275 if (description.hasGradient && description.hasBitmap) {
276 generatePorterDuffBlend(shader, "blendShaders", description.shadersMode);
277 }
278 if (description.colorOp == ProgramDescription::kColorBlend) {
279 generatePorterDuffBlend(shader, "blendColors", description.colorMode);
280 }
281
282 // Begin the shader
283 shader.append(gFS_Main); {
284 // Stores the result in fragColor directly
285 if (description.hasTexture) {
286 if (description.hasAlpha8Texture) {
287 shader.append(gFS_Main_FetchA8Texture);
288 } else {
289 shader.append(gFS_Main_FetchTexture);
290 }
291 } else {
292 shader.append(gFS_Main_FetchColor);
293 }
294 if (description.hasGradient) {
295 shader.append(gFS_Main_FetchGradient);
296 }
297 if (description.hasBitmap) {
298 shader.append(gFS_Main_FetchBitmap);
299 }
300 // Case when we have two shaders set
301 if (description.hasGradient && description.hasBitmap) {
302 if (description.isBitmapFirst) {
303 shader.append(gFS_Main_BlendShadersBG);
304 } else {
305 shader.append(gFS_Main_BlendShadersGB);
306 }
307 shader.append(gFS_Main_BlendShaders_Modulate);
308 }
309 // Apply the color op if needed
310 shader.append(gFS_Main_ApplyColorOp[description.colorOp]);
311 // Output the fragment
312 shader.append(gFS_Main_FragColor);
313 }
314 // End the shader
315 shader.append(gFS_Footer);
316
317 PROGRAM_LOGD("*** Generated fragment shader:\n\n%s", shader.string());
318 return shader;
319}
320
321void ProgramCache::generatePorterDuffBlend(String8& shader, const char* name,
322 SkXfermode::Mode mode) {
323 shader.append("\nvec4 ");
324 shader.append(name);
325 shader.append("(vec4 src, vec4 dst) {\n");
326 shader.append(" ");
327 shader.append(gPorterDuff[mode]);
328 shader.append("}\n");
329}
330
331}; // namespace uirenderer
332}; // namespace android