885fec78687ce43af5777e8e117b948efa401bcd
[WebKit-https.git] / Source / WebCore / platform / graphics / texmap / TextureMapperShaderProgram.cpp
1 /*
2  Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)
3  Copyright (C) 2012 Igalia S.L.
4  Copyright (C) 2011 Google Inc. All rights reserved.
5
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Library General Public
8  License as published by the Free Software Foundation; either
9  version 2 of the License, or (at your option) any later version.
10
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  Library General Public License for more details.
15
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB.  If not, write to
18  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  Boston, MA 02110-1301, USA.
20  */
21
22 #include "config.h"
23 #include "TextureMapperShaderProgram.h"
24
25 #if USE(TEXTURE_MAPPER)
26 #include "LengthFunctions.h"
27 #include "Logging.h"
28 #include "TextureMapperGL.h"
29
30 #include <wtf/text/StringBuilder.h>
31
32 #define STRINGIFY(...) #__VA_ARGS__
33
34 namespace WebCore {
35
36 static inline bool compositingLogEnabled()
37 {
38 #if !LOG_DISABLED
39     return LogCompositing.state == WTFLogChannelOn;
40 #else
41     return false;
42 #endif
43 }
44
45 TextureMapperShaderProgram::TextureMapperShaderProgram(PassRefPtr<GraphicsContext3D> context, const String& vertex, const String& fragment)
46     : m_context(context)
47 {
48     m_vertexShader = m_context->createShader(GraphicsContext3D::VERTEX_SHADER);
49     m_fragmentShader = m_context->createShader(GraphicsContext3D::FRAGMENT_SHADER);
50     m_context->shaderSource(m_vertexShader, vertex);
51     m_context->shaderSource(m_fragmentShader, fragment);
52     m_id = m_context->createProgram();
53     m_context->compileShader(m_vertexShader);
54     m_context->compileShader(m_fragmentShader);
55     m_context->attachShader(m_id, m_vertexShader);
56     m_context->attachShader(m_id, m_fragmentShader);
57     m_context->linkProgram(m_id);
58
59     if (!compositingLogEnabled())
60         return;
61
62     if (m_context->getError() == GraphicsContext3D::NO_ERROR)
63         return;
64
65     String log = m_context->getShaderInfoLog(m_vertexShader);
66     LOG(Compositing, "Vertex shader log: %s\n", log.utf8().data());
67     log = m_context->getShaderInfoLog(m_fragmentShader);
68     LOG(Compositing, "Fragment shader log: %s\n", log.utf8().data());
69     log = m_context->getProgramInfoLog(m_id);
70     LOG(Compositing, "Program log: %s\n", log.utf8().data());
71 }
72
73 void TextureMapperShaderProgram::setMatrix(GC3Duint location, const TransformationMatrix& matrix)
74 {
75     GC3Dfloat matrixAsFloats[] = {
76         GC3Dfloat(matrix.m11()), GC3Dfloat(matrix.m12()), GC3Dfloat(matrix.m13()), GC3Dfloat(matrix.m14()),
77         GC3Dfloat(matrix.m21()), GC3Dfloat(matrix.m22()), GC3Dfloat(matrix.m23()), GC3Dfloat(matrix.m24()),
78         GC3Dfloat(matrix.m31()), GC3Dfloat(matrix.m32()), GC3Dfloat(matrix.m33()), GC3Dfloat(matrix.m34()),
79         GC3Dfloat(matrix.m41()), GC3Dfloat(matrix.m42()), GC3Dfloat(matrix.m43()), GC3Dfloat(matrix.m44())
80     };
81
82     m_context->uniformMatrix4fv(location, 1, false, matrixAsFloats);
83 }
84
85 GC3Duint TextureMapperShaderProgram::getLocation(const AtomicString& name, VariableType type)
86 {
87     HashMap<AtomicString, GC3Duint>::iterator it = m_variables.find(name);
88     if (it != m_variables.end())
89         return it->value;
90
91     GC3Duint location = 0;
92     switch (type) {
93     case UniformVariable:
94         location = m_context->getUniformLocation(m_id, name);
95         break;
96     case AttribVariable:
97         location = m_context->getAttribLocation(m_id, name);
98         break;
99     default:
100         ASSERT_NOT_REACHED();
101         break;
102     }
103
104     m_variables.add(name, location);
105     return location;
106 }
107
108 TextureMapperShaderProgram::~TextureMapperShaderProgram()
109 {
110     Platform3DObject programID = m_id;
111     if (!programID)
112         return;
113
114     m_context->detachShader(programID, m_vertexShader);
115     m_context->deleteShader(m_vertexShader);
116     m_context->detachShader(programID, m_fragmentShader);
117     m_context->deleteShader(m_fragmentShader);
118     m_context->deleteProgram(programID);
119 }
120
121 #define GLSL_DIRECTIVE(...) "#"#__VA_ARGS__"\n"
122
123 #define TEXTURE_SPACE_MATRIX_PRECISION_DIRECTIVE \
124     GLSL_DIRECTIVE(ifdef GL_FRAGMENT_PRECISION_HIGH) \
125         GLSL_DIRECTIVE(define TextureSpaceMatrixPrecision highp) \
126     GLSL_DIRECTIVE(else) \
127         GLSL_DIRECTIVE(define TextureSpaceMatrixPrecision mediump) \
128     GLSL_DIRECTIVE(endif)
129
130 static const char* vertexTemplate =
131     TEXTURE_SPACE_MATRIX_PRECISION_DIRECTIVE
132     STRINGIFY(
133         precision TextureSpaceMatrixPrecision float;
134         attribute vec4 a_vertex;
135         uniform mat4 u_modelViewMatrix;
136         uniform mat4 u_projectionMatrix;
137         uniform mat4 u_textureSpaceMatrix;
138
139         varying vec2 v_texCoord;
140         varying vec2 v_transformedTexCoord;
141         varying float v_antialias;
142
143         void noop(inout vec2 dummyParameter) { }
144
145         vec4 toViewportSpace(vec2 pos) { return vec4(pos, 0., 1.) * u_modelViewMatrix; }
146
147         // This function relies on the assumption that we get edge triangles with control points,
148         // a control point being the nearest point to the coordinate that is on the edge.
149         void applyAntialiasing(inout vec2 position)
150         {
151             // We count on the fact that quad passed in is always a unit rect,
152             // and the transformation matrix applies the real rect.
153             const vec2 center = vec2(0.5, 0.5);
154             const float antialiasInflationDistance = 1.;
155
156             // We pass the control point as the zw coordinates of the vertex.
157             // The control point is the point on the edge closest to the current position.
158             // The control point is used to compute the antialias value.
159             vec2 controlPoint = a_vertex.zw;
160
161             // First we calculate the distance in viewport space.
162             vec4 centerInViewportCoordinates = toViewportSpace(center);
163             vec4 controlPointInViewportCoordinates = toViewportSpace(controlPoint);
164             float viewportSpaceDistance = distance(centerInViewportCoordinates, controlPointInViewportCoordinates);
165
166             // We add the inflation distance to the computed distance, and compute the ratio.
167             float inflationRatio = (viewportSpaceDistance + antialiasInflationDistance) / viewportSpaceDistance;
168
169             // v_antialias needs to be 0 for the outer edge and 1. for the inner edge.
170             // Since the controlPoint is equal to the position in the edge vertices, the value is always 0 for those.
171             // For the center point, the distance is always 0.5, so we normalize to 1. by multiplying by 2.
172             // By multplying by inflationRatio and dividing by (inflationRatio - 1),
173             // We make sure that the varying interpolates between 0 (outer edge), 1 (inner edge) and n > 1 (center).
174             v_antialias = distance(controlPoint, position) * 2. * inflationRatio / (inflationRatio - 1.);
175
176             // Now inflate the actual position. By using this formula instead of inflating position directly,
177             // we ensure that the center vertex is never inflated.
178             position = center + (position - center) * inflationRatio;
179         }
180
181         void main(void)
182         {
183             vec2 position = a_vertex.xy;
184             applyAntialiasingIfNeeded(position);
185
186             v_texCoord = position;
187             vec4 clampedPosition = clamp(vec4(position, 0., 1.), 0., 1.);
188             v_transformedTexCoord = (u_textureSpaceMatrix * clampedPosition).xy;
189             gl_Position = u_projectionMatrix * u_modelViewMatrix * vec4(position, 0., 1.);
190         }
191     );
192
193 #define RECT_TEXTURE_DIRECTIVE \
194     GLSL_DIRECTIVE(ifdef ENABLE_Rect) \
195         GLSL_DIRECTIVE(define SamplerType sampler2DRect) \
196         GLSL_DIRECTIVE(define SamplerFunction texture2DRect) \
197     GLSL_DIRECTIVE(else) \
198         GLSL_DIRECTIVE(define SamplerType sampler2D) \
199         GLSL_DIRECTIVE(define SamplerFunction texture2D) \
200     GLSL_DIRECTIVE(endif)
201
202 #define ANTIALIASING_TEX_COORD_DIRECTIVE \
203     GLSL_DIRECTIVE(if defined(ENABLE_Antialiasing) && defined(ENABLE_Texture)) \
204         GLSL_DIRECTIVE(define transformTexCoord fragmentTransformTexCoord) \
205     GLSL_DIRECTIVE(else) \
206         GLSL_DIRECTIVE(define transformTexCoord vertexTransformTexCoord) \
207     GLSL_DIRECTIVE(endif)
208
209 #define ENABLE_APPLIER(Name) "#define ENABLE_"#Name"\n#define apply"#Name"IfNeeded apply"#Name"\n"
210 #define DISABLE_APPLIER(Name) "#define apply"#Name"IfNeeded noop\n"
211 #define BLUR_CONSTANTS \
212     GLSL_DIRECTIVE(define GAUSSIAN_KERNEL_HALF_WIDTH 11) \
213     GLSL_DIRECTIVE(define GAUSSIAN_KERNEL_STEP 0.2)
214
215
216 static const char* fragmentTemplate =
217     RECT_TEXTURE_DIRECTIVE
218     ANTIALIASING_TEX_COORD_DIRECTIVE
219     BLUR_CONSTANTS
220     TEXTURE_SPACE_MATRIX_PRECISION_DIRECTIVE
221     STRINGIFY(
222         precision TextureSpaceMatrixPrecision float;
223         uniform mat4 u_textureSpaceMatrix;
224         precision mediump float;
225         uniform SamplerType s_sampler;
226         uniform sampler2D s_contentTexture;
227         uniform float u_opacity;
228         varying float v_antialias;
229         varying vec2 v_texCoord;
230         varying vec2 v_transformedTexCoord;
231         uniform float u_filterAmount;
232         uniform vec2 u_blurRadius;
233         uniform vec2 u_shadowOffset;
234         uniform vec4 u_color;
235         uniform float u_gaussianKernel[GAUSSIAN_KERNEL_HALF_WIDTH];
236
237         void noop(inout vec4 dummyParameter) { }
238         void noop(inout vec4 dummyParameter, vec2 texCoord) { }
239
240         float antialias() { return smoothstep(0., 1., v_antialias); }
241
242         vec2 fragmentTransformTexCoord()
243         {
244             vec4 clampedPosition = clamp(vec4(v_texCoord, 0., 1.), 0., 1.);
245             return (u_textureSpaceMatrix * clampedPosition).xy;
246         }
247
248         vec2 vertexTransformTexCoord() { return v_transformedTexCoord; }
249
250         void applyTexture(inout vec4 color, vec2 texCoord) { color = SamplerFunction(s_sampler, texCoord); }
251         void applyOpacity(inout vec4 color) { color *= u_opacity; }
252         void applyAntialiasing(inout vec4 color) { color *= antialias(); }
253
254         void applyGrayscaleFilter(inout vec4 color)
255         {
256             float amount = 1.0 - u_filterAmount;
257             color = vec4((0.2126 + 0.7874 * amount) * color.r + (0.7152 - 0.7152 * amount) * color.g + (0.0722 - 0.0722 * amount) * color.b,
258                 (0.2126 - 0.2126 * amount) * color.r + (0.7152 + 0.2848 * amount) * color.g + (0.0722 - 0.0722 * amount) * color.b,
259                 (0.2126 - 0.2126 * amount) * color.r + (0.7152 - 0.7152 * amount) * color.g + (0.0722 + 0.9278 * amount) * color.b,
260                 color.a);
261         }
262
263         void applySepiaFilter(inout vec4 color)
264         {
265             float amount = 1.0 - u_filterAmount;
266             color = vec4((0.393 + 0.607 * amount) * color.r + (0.769 - 0.769 * amount) * color.g + (0.189 - 0.189 * amount) * color.b,
267                 (0.349 - 0.349 * amount) * color.r + (0.686 + 0.314 * amount) * color.g + (0.168 - 0.168 * amount) * color.b,
268                 (0.272 - 0.272 * amount) * color.r + (0.534 - 0.534 * amount) * color.g + (0.131 + 0.869 * amount) * color.b,
269                 color.a);
270         }
271
272         void applySaturateFilter(inout vec4 color)
273         {
274             color = vec4((0.213 + 0.787 * u_filterAmount) * color.r + (0.715 - 0.715 * u_filterAmount) * color.g + (0.072 - 0.072 * u_filterAmount) * color.b,
275                 (0.213 - 0.213 * u_filterAmount) * color.r + (0.715 + 0.285 * u_filterAmount) * color.g + (0.072 - 0.072 * u_filterAmount) * color.b,
276                 (0.213 - 0.213 * u_filterAmount) * color.r + (0.715 - 0.715 * u_filterAmount) * color.g + (0.072 + 0.928 * u_filterAmount) * color.b,
277                 color.a);
278         }
279
280         void applyHueRotateFilter(inout vec4 color)
281         {
282             float pi = 3.14159265358979323846;
283             float c = cos(u_filterAmount * pi / 180.0);
284             float s = sin(u_filterAmount * pi / 180.0);
285             color = vec4(color.r * (0.213 + c * 0.787 - s * 0.213) + color.g * (0.715 - c * 0.715 - s * 0.715) + color.b * (0.072 - c * 0.072 + s * 0.928),
286                 color.r * (0.213 - c * 0.213 + s * 0.143) + color.g * (0.715 + c * 0.285 + s * 0.140) + color.b * (0.072 - c * 0.072 - s * 0.283),
287                 color.r * (0.213 - c * 0.213 - s * 0.787) +  color.g * (0.715 - c * 0.715 + s * 0.715) + color.b * (0.072 + c * 0.928 + s * 0.072),
288                 color.a);
289         }
290
291         float invert(float n) { return (1.0 - n) * u_filterAmount + n * (1.0 - u_filterAmount); }
292         void applyInvertFilter(inout vec4 color)
293         {
294             color = vec4(invert(color.r), invert(color.g), invert(color.b), color.a);
295         }
296
297         void applyBrightnessFilter(inout vec4 color)
298         {
299             color = vec4(color.rgb * u_filterAmount, color.a);
300         }
301
302         float contrast(float n) { return (n - 0.5) * u_filterAmount + 0.5; }
303         void applyContrastFilter(inout vec4 color)
304         {
305             color = vec4(contrast(color.r), contrast(color.g), contrast(color.b), color.a);
306         }
307
308         void applyOpacityFilter(inout vec4 color)
309         {
310             color = vec4(color.r, color.g, color.b, color.a * u_filterAmount);
311         }
312
313         vec4 sampleColorAtRadius(float radius, vec2 texCoord)
314         {
315             vec2 coord = texCoord + radius * u_blurRadius;
316             return SamplerFunction(s_sampler, coord) * float(coord.x > 0. && coord.y > 0. && coord.x < 1. && coord.y < 1.);
317         }
318
319         float sampleAlphaAtRadius(float radius, vec2 texCoord)
320         {
321             vec2 coord = texCoord - u_shadowOffset + radius * u_blurRadius;
322             return SamplerFunction(s_sampler, coord).a * float(coord.x > 0. && coord.y > 0. && coord.x < 1. && coord.y < 1.);
323         }
324
325         void applyBlurFilter(inout vec4 color, vec2 texCoord)
326         {
327             vec4 total = sampleColorAtRadius(0., texCoord) * u_gaussianKernel[0];
328             for (int i = 1; i < GAUSSIAN_KERNEL_HALF_WIDTH; i++) {
329                 total += sampleColorAtRadius(float(i) * GAUSSIAN_KERNEL_STEP, texCoord) * u_gaussianKernel[i];
330                 total += sampleColorAtRadius(float(-1 * i) * GAUSSIAN_KERNEL_STEP, texCoord) * u_gaussianKernel[i];
331             }
332
333             color = total;
334         }
335
336         void applyAlphaBlur(inout vec4 color, vec2 texCoord)
337         {
338             float total = sampleAlphaAtRadius(0., texCoord) * u_gaussianKernel[0];
339             for (int i = 1; i < GAUSSIAN_KERNEL_HALF_WIDTH; i++) {
340                 total += sampleAlphaAtRadius(float(i) * GAUSSIAN_KERNEL_STEP, texCoord) * u_gaussianKernel[i];
341                 total += sampleAlphaAtRadius(float(-1 * i) * GAUSSIAN_KERNEL_STEP, texCoord) * u_gaussianKernel[i];
342             }
343
344             color *= total;
345         }
346
347         vec4 sourceOver(vec4 src, vec4 dst) { return src + dst * (1. - dst.a); }
348
349         void applyContentTexture(inout vec4 color, vec2 texCoord)
350         {
351             vec4 contentColor = texture2D(s_contentTexture, texCoord);
352             color = sourceOver(contentColor, color);
353         }
354
355         void applySolidColor(inout vec4 color) { color *= u_color; }
356
357         void main(void)
358         {
359             vec4 color = vec4(1., 1., 1., 1.);
360             vec2 texCoord = transformTexCoord();
361             applyTextureIfNeeded(color, texCoord);
362             applySolidColorIfNeeded(color);
363             applyAntialiasingIfNeeded(color);
364             applyOpacityIfNeeded(color);
365             applyGrayscaleFilterIfNeeded(color);
366             applySepiaFilterIfNeeded(color);
367             applySaturateFilterIfNeeded(color);
368             applyHueRotateFilterIfNeeded(color);
369             applyInvertFilterIfNeeded(color);
370             applyBrightnessFilterIfNeeded(color);
371             applyContrastFilterIfNeeded(color);
372             applyOpacityFilterIfNeeded(color);
373             applyBlurFilterIfNeeded(color, texCoord);
374             applyAlphaBlurIfNeeded(color, texCoord);
375             applyContentTextureIfNeeded(color, texCoord);
376             gl_FragColor = color;
377         }
378     );
379
380 PassRefPtr<TextureMapperShaderProgram> TextureMapperShaderProgram::create(PassRefPtr<GraphicsContext3D> context, TextureMapperShaderProgram::Options options)
381 {
382     StringBuilder shaderBuilder;
383 #define SET_APPLIER_FROM_OPTIONS(Applier) \
384     shaderBuilder.append(\
385         (options & TextureMapperShaderProgram::Applier) ? ENABLE_APPLIER(Applier) : DISABLE_APPLIER(Applier))
386
387     SET_APPLIER_FROM_OPTIONS(Texture);
388     SET_APPLIER_FROM_OPTIONS(Rect);
389     SET_APPLIER_FROM_OPTIONS(SolidColor);
390     SET_APPLIER_FROM_OPTIONS(Opacity);
391     SET_APPLIER_FROM_OPTIONS(Antialiasing);
392     SET_APPLIER_FROM_OPTIONS(GrayscaleFilter);
393     SET_APPLIER_FROM_OPTIONS(SepiaFilter);
394     SET_APPLIER_FROM_OPTIONS(SaturateFilter);
395     SET_APPLIER_FROM_OPTIONS(HueRotateFilter);
396     SET_APPLIER_FROM_OPTIONS(BrightnessFilter);
397     SET_APPLIER_FROM_OPTIONS(ContrastFilter);
398     SET_APPLIER_FROM_OPTIONS(InvertFilter);
399     SET_APPLIER_FROM_OPTIONS(OpacityFilter);
400     SET_APPLIER_FROM_OPTIONS(BlurFilter);
401     SET_APPLIER_FROM_OPTIONS(AlphaBlur);
402     SET_APPLIER_FROM_OPTIONS(ContentTexture);
403     StringBuilder vertexBuilder;
404     vertexBuilder.append(shaderBuilder.toString());
405     vertexBuilder.append(vertexTemplate);
406     shaderBuilder.append(fragmentTemplate);
407
408     String vertexSource = vertexBuilder.toString();
409     String fragmentSource = shaderBuilder.toString();
410
411     return adoptRef(new TextureMapperShaderProgram(context, vertexSource, fragmentSource));
412 }
413
414 }
415 #endif