1 /*
2 * Copyright (c) 2010, Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "config.h"
32
33 #if ENABLE(ACCELERATED_2D_CANVAS)
34
35 #include "Shader.h"
36
37 #include "AffineTransform.h"
38 #include "GraphicsContext3D.h"
39
40 #include <wtf/text/CString.h>
41 #include <wtf/text/StringBuilder.h>
42
43 namespace WebCore {
44
45 // static
affineTo3x3(const AffineTransform & transform,float mat[9])46 void Shader::affineTo3x3(const AffineTransform& transform, float mat[9])
47 {
48 mat[0] = transform.a();
49 mat[1] = transform.b();
50 mat[2] = 0.0f;
51 mat[3] = transform.c();
52 mat[4] = transform.d();
53 mat[5] = 0.0f;
54 mat[6] = transform.e();
55 mat[7] = transform.f();
56 mat[8] = 1.0f;
57 }
58
59 // static
affineTo4x4(const AffineTransform & transform,float mat[16])60 void Shader::affineTo4x4(const AffineTransform& transform, float mat[16])
61 {
62 mat[0] = transform.a();
63 mat[1] = transform.b();
64 mat[2] = 0.0f;
65 mat[3] = 0.0f;
66 mat[4] = transform.c();
67 mat[5] = transform.d();
68 mat[6] = 0.0f;
69 mat[7] = 0.0f;
70 mat[8] = 0.0f;
71 mat[9] = 0.0f;
72 mat[10] = 1.0f;
73 mat[11] = 0.0f;
74 mat[12] = transform.e();
75 mat[13] = transform.f();
76 mat[14] = 0.0f;
77 mat[15] = 1.0f;
78 }
79
80 // static
loadShader(GraphicsContext3D * context,unsigned type,const String & shaderSource)81 unsigned Shader::loadShader(GraphicsContext3D* context, unsigned type, const String& shaderSource)
82 {
83 unsigned shader = context->createShader(type);
84 if (!shader)
85 return 0;
86
87 context->shaderSource(shader, shaderSource);
88 context->compileShader(shader);
89 int compileStatus = 0;
90 context->getShaderiv(shader, GraphicsContext3D::COMPILE_STATUS, &compileStatus);
91 if (!compileStatus) {
92 String infoLog = context->getShaderInfoLog(shader);
93 LOG_ERROR("%s", infoLog.utf8().data());
94 context->deleteShader(shader);
95 return 0;
96 }
97 return shader;
98 }
99
100 // static
loadProgram(GraphicsContext3D * context,const String & vertexShaderSource,const String & fragmentShaderSource)101 unsigned Shader::loadProgram(GraphicsContext3D* context, const String& vertexShaderSource, const String& fragmentShaderSource)
102 {
103 unsigned vertexShader = loadShader(context, GraphicsContext3D::VERTEX_SHADER, vertexShaderSource);
104 if (!vertexShader)
105 return 0;
106 unsigned fragmentShader = loadShader(context, GraphicsContext3D::FRAGMENT_SHADER, fragmentShaderSource);
107 if (!fragmentShader)
108 return 0;
109 unsigned program = context->createProgram();
110 if (!program)
111 return 0;
112 context->attachShader(program, vertexShader);
113 context->attachShader(program, fragmentShader);
114 context->linkProgram(program);
115 int linkStatus = 0;
116 context->getProgramiv(program, GraphicsContext3D::LINK_STATUS, &linkStatus);
117 if (!linkStatus)
118 context->deleteProgram(program);
119 context->deleteShader(vertexShader);
120 context->deleteShader(fragmentShader);
121 return program;
122 }
123
Shader(GraphicsContext3D * context,unsigned program)124 Shader::Shader(GraphicsContext3D* context, unsigned program)
125 : m_context(context)
126 , m_program(program)
127 {
128 }
129
~Shader()130 Shader::~Shader()
131 {
132 m_context->deleteProgram(m_program);
133 }
134
135 // static
generateVertex(Shader::VertexType vertexType,Shader::FillType fillType)136 String Shader::generateVertex(Shader::VertexType vertexType, Shader::FillType fillType)
137 {
138 StringBuilder builder;
139 switch (vertexType) {
140 case TwoDimensional:
141 builder.append(
142 "uniform mat3 matrix;\n"
143 "attribute vec2 position;\n");
144 break;
145 case LoopBlinnInterior:
146 builder.append(
147 "uniform mat4 worldViewProjection;\n"
148 "attribute vec2 position;\n");
149 break;
150 case LoopBlinnExterior:
151 builder.append(
152 "uniform mat4 worldViewProjection;\n"
153 "attribute vec2 position;\n"
154 "attribute vec3 klm;\n"
155 "varying vec3 v_klm;\n");
156 break;
157 }
158
159 if (fillType == TextureFill) {
160 builder.append(
161 "uniform mat3 texMatrix;\n"
162 "varying vec3 texCoord;\n");
163 }
164
165 builder.append(
166 "void main() {\n");
167
168 if (vertexType == TwoDimensional) {
169 builder.append(
170 "gl_Position = vec4(matrix * vec3(position, 1.0), 1.0);\n");
171 } else {
172 builder.append(
173 "gl_Position = worldViewProjection * vec4(position, 0.0, 1.0);\n");
174 if (vertexType == LoopBlinnExterior) {
175 builder.append(
176 "v_klm = klm;\n");
177 }
178 }
179
180 if (fillType == TextureFill) {
181 builder.append(
182 "texCoord = texMatrix * vec3(position, 1.0);\n");
183 }
184
185 builder.append(
186 "}\n");
187
188 return builder.toString();
189 }
190
191 // static
generateFragment(Shader::VertexType vertexType,Shader::FillType fillType,Shader::AntialiasType antialiasType)192 String Shader::generateFragment(Shader::VertexType vertexType, Shader::FillType fillType, Shader::AntialiasType antialiasType)
193 {
194 StringBuilder builder;
195 builder.append(
196 "#ifdef GL_ES\n"
197 "precision mediump float;\n"
198 "#endif\n");
199
200 if (vertexType == LoopBlinnExterior) {
201 if (antialiasType == Antialiased) {
202 builder.append(
203 "#extension GL_OES_standard_derivatives : enable\n");
204 }
205 builder.append(
206 "varying vec3 v_klm;\n");
207 }
208
209 switch (fillType) {
210 case SolidFill:
211 builder.append(
212 "uniform vec4 color;\n");
213 break;
214 case TextureFill:
215 builder.append(
216 "uniform sampler2D sampler;\n"
217 "uniform float globalAlpha;\n"
218 "varying vec3 texCoord;\n");
219 break;
220 }
221
222 builder.append(
223 "void main() {\n");
224
225 if (vertexType != LoopBlinnExterior) {
226 builder.append(
227 "float alpha = 1.0;\n");
228 } else {
229 if (antialiasType == Antialiased) {
230 builder.append(
231 " // Gradients\n"
232 " vec3 px = dFdx(v_klm);\n"
233 " vec3 py = dFdy(v_klm);\n"
234 "\n"
235 " // Chain rule\n"
236 " float k2 = v_klm.x * v_klm.x;\n"
237 " float c = k2 * v_klm.x - v_klm.y * v_klm.z;\n"
238 " float k23 = 3.0 * k2;\n"
239 " float cx = k23 * px.x - v_klm.z * px.y - v_klm.y * px.z;\n"
240 " float cy = k23 * py.x - v_klm.z * py.y - v_klm.y * py.z;\n"
241 "\n"
242 " // Signed distance\n"
243 " float sd = c / sqrt(cx * cx + cy * cy);\n"
244 "\n"
245 " // Linear alpha\n"
246 " // FIXME: figure out why this needs to be\n"
247 " // negated compared to the HLSL version, and also why\n"
248 " // we need an adjustment by +1.0 for it to look good.\n"
249 " // float alpha = clamp(0.5 - sd, 0.0, 1.0);\n"
250 " float alpha = clamp(sd + 0.5, 0.0, 1.0);\n");
251 } else {
252 builder.append(
253 " float t = v_klm.x * v_klm.x * v_klm.x - v_klm.y * v_klm.z;\n"
254 " float alpha = clamp(sign(t), 0.0, 1.0);\n");
255 }
256 }
257
258 switch (fillType) {
259 case SolidFill:
260 builder.append(
261 "gl_FragColor = color * alpha;\n");
262 break;
263 case TextureFill:
264 builder.append(
265 "gl_FragColor = texture2D(sampler, texCoord.xy) * alpha * globalAlpha;\n");
266 break;
267 }
268
269 builder.append(
270 "}\n");
271
272 return builder.toString();
273 }
274
275 } // namespace WebCore
276
277 #endif
278