initial import
[vuplus_webkit] / Source / WebCore / platform / graphics / gpu / Shader.cpp
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
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
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
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
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
124 Shader::Shader(GraphicsContext3D* context, unsigned program)
125     : m_context(context)
126     , m_program(program)
127 {
128 }
129
130 Shader::~Shader()
131 {
132     m_context->deleteProgram(m_program);
133 }
134
135 // static
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
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