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(ACCELERATED_COMPOSITING) && 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 34namespace WebCore { 35 36static inline bool compositingLogEnabled() 37{ 38#if !LOG_DISABLED 39 return LogCompositing.state == WTFLogChannelOn; 40#else 41 return false; 42#endif 43} 44 45TextureMapperShaderProgram::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 73void 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 85GC3Duint 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 108TextureMapperShaderProgram::~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" 122static const char* vertexTemplate = 123 STRINGIFY( 124 attribute vec4 a_vertex; 125 uniform mat4 u_modelViewMatrix; 126 uniform mat4 u_projectionMatrix; 127 uniform mat4 u_textureSpaceMatrix; 128 129 varying vec2 v_texCoord; 130 varying float v_antialias; 131 132 void noop(inout vec2 dummyParameter) { } 133 134 vec4 toViewportSpace(vec2 pos) { return vec4(pos, 0., 1.) * u_modelViewMatrix; } 135 136 // This function relies on the assumption that we get edge triangles with control points, 137 // a control point being the nearest point to the coordinate that is on the edge. 138 void applyAntialiasing(inout vec2 position) 139 { 140 // We count on the fact that quad passed in is always a unit rect, 141 // and the transformation matrix applies the real rect. 142 const vec2 center = vec2(0.5, 0.5); 143 const float antialiasInflationDistance = 1.; 144 145 // We pass the control point as the zw coordinates of the vertex. 146 // The control point is the point on the edge closest to the current position. 147 // The control point is used to compute the antialias value. 148 vec2 controlPoint = a_vertex.zw; 149 150 // First we calculate the distance in viewport space. 151 vec4 centerInViewportCoordinates = toViewportSpace(center); 152 vec4 controlPointInViewportCoordinates = toViewportSpace(controlPoint); 153 float viewportSpaceDistance = distance(centerInViewportCoordinates, controlPointInViewportCoordinates); 154 155 // We add the inflation distance to the computed distance, and compute the ratio. 156 float inflationRatio = (viewportSpaceDistance + antialiasInflationDistance) / viewportSpaceDistance; 157 158 // v_antialias needs to be 0 for the outer edge and 1. for the inner edge. 159 // Since the controlPoint is equal to the position in the edge vertices, the value is always 0 for those. 160 // For the center point, the distance is always 0.5, so we normalize to 1. by multiplying by 2. 161 // By multplying by inflationRatio and dividing by (inflationRatio - 1), 162 // We make sure that the varying interpolates between 0 (outer edge), 1 (inner edge) and n > 1 (center). 163 v_antialias = distance(controlPoint, position) * 2. * inflationRatio / (inflationRatio - 1.); 164 165 // Now inflate the actual position. By using this formula instead of inflating position directly, 166 // we ensure that the center vertex is never inflated. 167 position = center + (position - center) * inflationRatio; 168 } 169 170 void main(void) 171 { 172 vec2 position = a_vertex.xy; 173 applyAntialiasingIfNeeded(position); 174 175 // The texture position needs to be clamped to 0..1 before the texture matrix is applied. 176 vec4 clampedPosition = clamp(vec4(position, 0., 1.), 0., 1.); 177 v_texCoord = (u_textureSpaceMatrix * clampedPosition).xy; 178 gl_Position = u_projectionMatrix * u_modelViewMatrix * vec4(position, 0., 1.); 179 } 180 ); 181 182#define RECT_TEXTURE_DIRECTIVE \ 183 GLSL_DIRECTIVE(ifdef ENABLE_Rect) \ 184 GLSL_DIRECTIVE(define SamplerType sampler2DRect) \ 185 GLSL_DIRECTIVE(define SamplerFunction texture2DRect) \ 186 GLSL_DIRECTIVE(else) \ 187 GLSL_DIRECTIVE(define SamplerType sampler2D) \ 188 GLSL_DIRECTIVE(define SamplerFunction texture2D) \ 189 GLSL_DIRECTIVE(endif) 190 191#define ENABLE_APPLIER(Name) "#define ENABLE_"#Name"\n#define apply"#Name"IfNeeded apply"#Name"\n" 192#define DISABLE_APPLIER(Name) "#define apply"#Name"IfNeeded noop\n" 193#define BLUR_CONSTANTS \ 194 GLSL_DIRECTIVE(define GAUSSIAN_KERNEL_HALF_WIDTH 11) \ 195 GLSL_DIRECTIVE(define GAUSSIAN_KERNEL_STEP 0.2) 196 197 198static const char* fragmentTemplate = 199 RECT_TEXTURE_DIRECTIVE 200 BLUR_CONSTANTS 201 STRINGIFY( 202 precision mediump float; 203 uniform SamplerType s_sampler; 204 uniform sampler2D s_contentTexture; 205 uniform float u_opacity; 206 varying float v_antialias; 207 varying vec2 v_texCoord; 208 uniform float u_filterAmount; 209 uniform vec2 u_blurRadius; 210 uniform vec2 u_shadowOffset; 211 uniform vec4 u_color; 212 uniform float u_gaussianKernel[GAUSSIAN_KERNEL_HALF_WIDTH]; 213 214 void noop(inout vec4 dummyParameter) { } 215 216 float antialias() { return smoothstep(v_antialias, 0., 1.); } 217 218 void applyTexture(inout vec4 color) { color = SamplerFunction(s_sampler, v_texCoord); } 219 void applyOpacity(inout vec4 color) { color *= u_opacity; } 220 void applyAntialiasing(inout vec4 color) { color *= antialias(); } 221 222 void applyGrayscaleFilter(inout vec4 color) 223 { 224 float amount = 1.0 - u_filterAmount; 225 color = vec4((0.2126 + 0.7874 * amount) * color.r + (0.7152 - 0.7152 * amount) * color.g + (0.0722 - 0.0722 * amount) * color.b, 226 (0.2126 - 0.2126 * amount) * color.r + (0.7152 + 0.2848 * amount) * color.g + (0.0722 - 0.0722 * amount) * color.b, 227 (0.2126 - 0.2126 * amount) * color.r + (0.7152 - 0.7152 * amount) * color.g + (0.0722 + 0.9278 * amount) * color.b, 228 color.a); 229 } 230 231 void applySepiaFilter(inout vec4 color) 232 { 233 float amount = 1.0 - u_filterAmount; 234 color = vec4((0.393 + 0.607 * amount) * color.r + (0.769 - 0.769 * amount) * color.g + (0.189 - 0.189 * amount) * color.b, 235 (0.349 - 0.349 * amount) * color.r + (0.686 + 0.314 * amount) * color.g + (0.168 - 0.168 * amount) * color.b, 236 (0.272 - 0.272 * amount) * color.r + (0.534 - 0.534 * amount) * color.g + (0.131 + 0.869 * amount) * color.b, 237 color.a); 238 } 239 240 void applySaturateFilter(inout vec4 color) 241 { 242 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, 243 (0.213 - 0.213 * u_filterAmount) * color.r + (0.715 + 0.285 * u_filterAmount) * color.g + (0.072 - 0.072 * u_filterAmount) * color.b, 244 (0.213 - 0.213 * u_filterAmount) * color.r + (0.715 - 0.715 * u_filterAmount) * color.g + (0.072 + 0.928 * u_filterAmount) * color.b, 245 color.a); 246 } 247 248 void applyHueRotateFilter(inout vec4 color) 249 { 250 float pi = 3.14159265358979323846; 251 float c = cos(u_filterAmount * pi / 180.0); 252 float s = sin(u_filterAmount * pi / 180.0); 253 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), 254 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), 255 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), 256 color.a); 257 } 258 259 float invert(float n) { return (1.0 - n) * u_filterAmount + n * (1.0 - u_filterAmount); } 260 void applyInvertFilter(inout vec4 color) 261 { 262 color = vec4(invert(color.r), invert(color.g), invert(color.b), color.a); 263 } 264 265 void applyBrightnessFilter(inout vec4 color) 266 { 267 color = vec4(color.rgb * u_filterAmount, color.a); 268 } 269 270 float contrast(float n) { return (n - 0.5) * u_filterAmount + 0.5; } 271 void applyContrastFilter(inout vec4 color) 272 { 273 color = vec4(contrast(color.r), contrast(color.g), contrast(color.b), color.a); 274 } 275 276 void applyOpacityFilter(inout vec4 color) 277 { 278 color = vec4(color.r, color.g, color.b, color.a * u_filterAmount); 279 } 280 281 vec4 sampleColorAtRadius(float radius) 282 { 283 vec2 coord = v_texCoord + radius * u_blurRadius; 284 return SamplerFunction(s_sampler, coord) * float(coord.x > 0. && coord.y > 0. && coord.x < 1. && coord.y < 1.); 285 } 286 287 float sampleAlphaAtRadius(float radius) 288 { 289 vec2 coord = v_texCoord - u_shadowOffset + radius * u_blurRadius; 290 return SamplerFunction(s_sampler, coord).a * float(coord.x > 0. && coord.y > 0. && coord.x < 1. && coord.y < 1.); 291 } 292 293 void applyBlurFilter(inout vec4 color) 294 { 295 vec4 total = sampleColorAtRadius(0.) * u_gaussianKernel[0]; 296 for (int i = 1; i < GAUSSIAN_KERNEL_HALF_WIDTH; i++) { 297 total += sampleColorAtRadius(float(i) * GAUSSIAN_KERNEL_STEP) * u_gaussianKernel[i]; 298 total += sampleColorAtRadius(float(-1 * i) * GAUSSIAN_KERNEL_STEP) * u_gaussianKernel[i]; 299 } 300 301 color = total; 302 } 303 304 void applyAlphaBlur(inout vec4 color) 305 { 306 float total = sampleAlphaAtRadius(0.) * u_gaussianKernel[0]; 307 for (int i = 1; i < GAUSSIAN_KERNEL_HALF_WIDTH; i++) { 308 total += sampleAlphaAtRadius(float(i) * GAUSSIAN_KERNEL_STEP) * u_gaussianKernel[i]; 309 total += sampleAlphaAtRadius(float(-1 * i) * GAUSSIAN_KERNEL_STEP) * u_gaussianKernel[i]; 310 } 311 312 color *= total; 313 } 314 315 vec4 sourceOver(vec4 src, vec4 dst) { return src + dst * (1. - dst.a); } 316 317 void applyContentTexture(inout vec4 color) 318 { 319 vec4 contentColor = texture2D(s_contentTexture, v_texCoord); 320 color = sourceOver(contentColor, color); 321 } 322 323 void applySolidColor(inout vec4 color) { color *= u_color; } 324 325 void main(void) 326 { 327 vec4 color = vec4(1., 1., 1., 1.); 328 applyTextureIfNeeded(color); 329 applySolidColorIfNeeded(color); 330 applyAntialiasingIfNeeded(color); 331 applyOpacityIfNeeded(color); 332 applyGrayscaleFilterIfNeeded(color); 333 applySepiaFilterIfNeeded(color); 334 applySaturateFilterIfNeeded(color); 335 applyHueRotateFilterIfNeeded(color); 336 applyInvertFilterIfNeeded(color); 337 applyBrightnessFilterIfNeeded(color); 338 applyContrastFilterIfNeeded(color); 339 applyOpacityFilterIfNeeded(color); 340 applyBlurFilterIfNeeded(color); 341 applyAlphaBlurIfNeeded(color); 342 applyContentTextureIfNeeded(color); 343 gl_FragColor = color; 344 } 345 ); 346 347PassRefPtr<TextureMapperShaderProgram> TextureMapperShaderProgram::create(PassRefPtr<GraphicsContext3D> context, TextureMapperShaderProgram::Options options) 348{ 349 StringBuilder shaderBuilder; 350#define SET_APPLIER_FROM_OPTIONS(Applier) \ 351 shaderBuilder.append(\ 352 (options & TextureMapperShaderProgram::Applier) ? ENABLE_APPLIER(Applier) : DISABLE_APPLIER(Applier)) 353 354 SET_APPLIER_FROM_OPTIONS(Texture); 355 SET_APPLIER_FROM_OPTIONS(Rect); 356 SET_APPLIER_FROM_OPTIONS(SolidColor); 357 SET_APPLIER_FROM_OPTIONS(Opacity); 358 SET_APPLIER_FROM_OPTIONS(Antialiasing); 359 SET_APPLIER_FROM_OPTIONS(GrayscaleFilter); 360 SET_APPLIER_FROM_OPTIONS(SepiaFilter); 361 SET_APPLIER_FROM_OPTIONS(SaturateFilter); 362 SET_APPLIER_FROM_OPTIONS(HueRotateFilter); 363 SET_APPLIER_FROM_OPTIONS(BrightnessFilter); 364 SET_APPLIER_FROM_OPTIONS(ContrastFilter); 365 SET_APPLIER_FROM_OPTIONS(InvertFilter); 366 SET_APPLIER_FROM_OPTIONS(OpacityFilter); 367 SET_APPLIER_FROM_OPTIONS(BlurFilter); 368 SET_APPLIER_FROM_OPTIONS(AlphaBlur); 369 SET_APPLIER_FROM_OPTIONS(ContentTexture); 370 StringBuilder vertexBuilder; 371 vertexBuilder.append(shaderBuilder.toString()); 372 vertexBuilder.append(vertexTemplate); 373 shaderBuilder.append(fragmentTemplate); 374 375 String vertexSource = vertexBuilder.toString(); 376 String fragmentSource = shaderBuilder.toString(); 377 378 return adoptRef(new TextureMapperShaderProgram(context, vertexSource, fragmentSource)); 379} 380 381} 382#endif 383