| 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_GL) |
| 26 | |
| 27 | #include "GLContext.h" |
| 28 | #include "Logging.h" |
| 29 | #include "TextureMapperGL.h" |
| 30 | #include <wtf/text/StringBuilder.h> |
| 31 | |
| 32 | namespace WebCore { |
| 33 | |
| 34 | static inline bool compositingLogEnabled() |
| 35 | { |
| 36 | #if !LOG_DISABLED |
| 37 | return LogCompositing.state == WTFLogChannelState::On; |
| 38 | #else |
| 39 | return false; |
| 40 | #endif |
| 41 | } |
| 42 | |
| 43 | #define STRINGIFY(...) #__VA_ARGS__ |
| 44 | |
| 45 | #define GLSL_DIRECTIVE(...) "#"#__VA_ARGS__"\n" |
| 46 | |
| 47 | #define TEXTURE_SPACE_MATRIX_PRECISION_DIRECTIVE \ |
| 48 | GLSL_DIRECTIVE(ifdef GL_FRAGMENT_PRECISION_HIGH) \ |
| 49 | GLSL_DIRECTIVE(define TextureSpaceMatrixPrecision highp) \ |
| 50 | GLSL_DIRECTIVE(else) \ |
| 51 | GLSL_DIRECTIVE(define TextureSpaceMatrixPrecision mediump) \ |
| 52 | GLSL_DIRECTIVE(endif) |
| 53 | |
| 54 | |
| 55 | // Input/output variables definition for both GLES and OpenGL < 3.2. |
| 56 | // The default precision directive is only needed for GLES. |
| 57 | static const char* vertexTemplateLT320Vars = |
| 58 | #if USE(OPENGL_ES) |
| 59 | TEXTURE_SPACE_MATRIX_PRECISION_DIRECTIVE |
| 60 | #endif |
| 61 | #if USE(OPENGL_ES) |
| 62 | STRINGIFY( |
| 63 | precision TextureSpaceMatrixPrecision float; |
| 64 | ) |
| 65 | #endif |
| 66 | STRINGIFY( |
| 67 | attribute vec4 a_vertex; |
| 68 | varying vec2 v_texCoord; |
| 69 | varying vec2 v_transformedTexCoord; |
| 70 | varying float v_antialias; |
| 71 | ); |
| 72 | |
| 73 | #if !USE(OPENGL_ES) |
| 74 | // Input/output variables definition for OpenGL >= 3.2. |
| 75 | static const char* vertexTemplateGE320Vars = |
| 76 | STRINGIFY( |
| 77 | in vec4 a_vertex; |
| 78 | out vec2 v_texCoord; |
| 79 | out vec2 v_transformedTexCoord; |
| 80 | out float v_antialias; |
| 81 | ); |
| 82 | #endif |
| 83 | |
| 84 | static const char* vertexTemplateCommon = |
| 85 | STRINGIFY( |
| 86 | uniform mat4 u_modelViewMatrix; |
| 87 | uniform mat4 u_projectionMatrix; |
| 88 | uniform mat4 u_textureSpaceMatrix; |
| 89 | |
| 90 | void noop(inout vec2 dummyParameter) { } |
| 91 | |
| 92 | vec4 toViewportSpace(vec2 pos) { return vec4(pos, 0., 1.) * u_modelViewMatrix; } |
| 93 | |
| 94 | // This function relies on the assumption that we get edge triangles with control points, |
| 95 | // a control point being the nearest point to the coordinate that is on the edge. |
| 96 | void applyAntialiasing(inout vec2 position) |
| 97 | { |
| 98 | // We count on the fact that quad passed in is always a unit rect, |
| 99 | // and the transformation matrix applies the real rect. |
| 100 | const vec2 center = vec2(0.5, 0.5); |
| 101 | const float antialiasInflationDistance = 1.; |
| 102 | |
| 103 | // We pass the control point as the zw coordinates of the vertex. |
| 104 | // The control point is the point on the edge closest to the current position. |
| 105 | // The control point is used to compute the antialias value. |
| 106 | vec2 controlPoint = a_vertex.zw; |
| 107 | |
| 108 | // First we calculate the distance in viewport space. |
| 109 | vec4 centerInViewportCoordinates = toViewportSpace(center); |
| 110 | vec4 controlPointInViewportCoordinates = toViewportSpace(controlPoint); |
| 111 | float viewportSpaceDistance = distance(centerInViewportCoordinates, controlPointInViewportCoordinates); |
| 112 | |
| 113 | // We add the inflation distance to the computed distance, and compute the ratio. |
| 114 | float inflationRatio = (viewportSpaceDistance + antialiasInflationDistance) / viewportSpaceDistance; |
| 115 | |
| 116 | // v_antialias needs to be 0 for the outer edge and 1. for the inner edge. |
| 117 | // Since the controlPoint is equal to the position in the edge vertices, the value is always 0 for those. |
| 118 | // For the center point, the distance is always 0.5, so we normalize to 1. by multiplying by 2. |
| 119 | // By multplying by inflationRatio and dividing by (inflationRatio - 1), |
| 120 | // We make sure that the varying interpolates between 0 (outer edge), 1 (inner edge) and n > 1 (center). |
| 121 | v_antialias = distance(controlPoint, position) * 2. * inflationRatio / (inflationRatio - 1.); |
| 122 | |
| 123 | // Now inflate the actual position. By using this formula instead of inflating position directly, |
| 124 | // we ensure that the center vertex is never inflated. |
| 125 | position = center + (position - center) * inflationRatio; |
| 126 | } |
| 127 | |
| 128 | void main(void) |
| 129 | { |
| 130 | vec2 position = a_vertex.xy; |
| 131 | applyAntialiasingIfNeeded(position); |
| 132 | |
| 133 | v_texCoord = position; |
| 134 | vec4 clampedPosition = clamp(vec4(position, 0., 1.), 0., 1.); |
| 135 | v_transformedTexCoord = (u_textureSpaceMatrix * clampedPosition).xy; |
| 136 | gl_Position = u_projectionMatrix * u_modelViewMatrix * vec4(position, 0., 1.); |
| 137 | } |
| 138 | ); |
| 139 | |
| 140 | #define RECT_TEXTURE_DIRECTIVE \ |
| 141 | GLSL_DIRECTIVE(ifdef ENABLE_Rect) \ |
| 142 | GLSL_DIRECTIVE(define SamplerType sampler2DRect) \ |
| 143 | GLSL_DIRECTIVE(define SamplerFunction texture2DRect) \ |
| 144 | GLSL_DIRECTIVE(else) \ |
| 145 | GLSL_DIRECTIVE(define SamplerType sampler2D) \ |
| 146 | GLSL_DIRECTIVE(define SamplerFunction texture2D) \ |
| 147 | GLSL_DIRECTIVE(endif) |
| 148 | |
| 149 | #define ANTIALIASING_TEX_COORD_DIRECTIVE \ |
| 150 | GLSL_DIRECTIVE(if defined(ENABLE_Antialiasing) && defined(ENABLE_Texture)) \ |
| 151 | GLSL_DIRECTIVE(define transformTexCoord fragmentTransformTexCoord) \ |
| 152 | GLSL_DIRECTIVE(else) \ |
| 153 | GLSL_DIRECTIVE(define transformTexCoord vertexTransformTexCoord) \ |
| 154 | GLSL_DIRECTIVE(endif) |
| 155 | |
| 156 | #define ENABLE_APPLIER(Name) "#define ENABLE_"#Name"\n#define apply"#Name"IfNeeded apply"#Name"\n" |
| 157 | #define DISABLE_APPLIER(Name) "#define apply"#Name"IfNeeded noop\n" |
| 158 | #define BLUR_CONSTANTS \ |
| 159 | GLSL_DIRECTIVE(define GAUSSIAN_KERNEL_HALF_WIDTH 11) \ |
| 160 | GLSL_DIRECTIVE(define GAUSSIAN_KERNEL_STEP 0.2) |
| 161 | |
| 162 | |
| 163 | // Common header for all versions. We define the matrices variables here to keep the precision |
| 164 | // directives scope: the first one applies to the matrices variables and the next one to the |
| 165 | // rest of them. The precision is only used in GLES. |
| 166 | static const char* = |
| 167 | RECT_TEXTURE_DIRECTIVE |
| 168 | ANTIALIASING_TEX_COORD_DIRECTIVE |
| 169 | BLUR_CONSTANTS |
| 170 | #if USE(OPENGL_ES) |
| 171 | TEXTURE_SPACE_MATRIX_PRECISION_DIRECTIVE |
| 172 | #endif |
| 173 | #if USE(OPENGL_ES) |
| 174 | STRINGIFY( |
| 175 | precision TextureSpaceMatrixPrecision float; |
| 176 | ) |
| 177 | #endif |
| 178 | STRINGIFY( |
| 179 | uniform mat4 u_textureSpaceMatrix; |
| 180 | uniform mat4 u_textureColorSpaceMatrix; |
| 181 | ) |
| 182 | #if USE(OPENGL_ES) |
| 183 | STRINGIFY( |
| 184 | precision mediump float; |
| 185 | ) |
| 186 | #endif |
| 187 | ; |
| 188 | |
| 189 | // Input/output variables definition for both GLES and OpenGL < 3.2. |
| 190 | static const char* fragmentTemplateLT320Vars = |
| 191 | STRINGIFY( |
| 192 | varying float v_antialias; |
| 193 | varying vec2 v_texCoord; |
| 194 | varying vec2 v_transformedTexCoord; |
| 195 | ); |
| 196 | |
| 197 | #if !USE(OPENGL_ES) |
| 198 | // Input/output variables definition for OpenGL >= 3.2. |
| 199 | static const char* fragmentTemplateGE320Vars = |
| 200 | STRINGIFY( |
| 201 | in float v_antialias; |
| 202 | in vec2 v_texCoord; |
| 203 | in vec2 v_transformedTexCoord; |
| 204 | ); |
| 205 | #endif |
| 206 | |
| 207 | static const char* fragmentTemplateCommon = |
| 208 | STRINGIFY( |
| 209 | uniform SamplerType s_sampler; |
| 210 | uniform sampler2D s_contentTexture; |
| 211 | uniform float u_opacity; |
| 212 | uniform float u_filterAmount; |
| 213 | uniform vec2 u_blurRadius; |
| 214 | uniform vec2 u_shadowOffset; |
| 215 | uniform vec4 u_color; |
| 216 | uniform float u_gaussianKernel[GAUSSIAN_KERNEL_HALF_WIDTH]; |
| 217 | |
| 218 | void noop(inout vec4 dummyParameter) { } |
| 219 | void noop(inout vec4 dummyParameter, vec2 texCoord) { } |
| 220 | void noop(inout vec2 dummyParameter) { } |
| 221 | |
| 222 | float antialias() { return smoothstep(0., 1., v_antialias); } |
| 223 | |
| 224 | vec2 fragmentTransformTexCoord() |
| 225 | { |
| 226 | vec4 clampedPosition = clamp(vec4(v_texCoord, 0., 1.), 0., 1.); |
| 227 | return (u_textureSpaceMatrix * clampedPosition).xy; |
| 228 | } |
| 229 | |
| 230 | vec2 vertexTransformTexCoord() { return v_transformedTexCoord; } |
| 231 | |
| 232 | void applyManualRepeat(inout vec2 pos) { pos = fract(pos); } |
| 233 | |
| 234 | void applyTexture(inout vec4 color, vec2 texCoord) { color = u_textureColorSpaceMatrix * SamplerFunction(s_sampler, texCoord); } |
| 235 | void applyOpacity(inout vec4 color) { color *= u_opacity; } |
| 236 | void applyAntialiasing(inout vec4 color) { color *= antialias(); } |
| 237 | |
| 238 | void applyGrayscaleFilter(inout vec4 color) |
| 239 | { |
| 240 | float amount = 1.0 - u_filterAmount; |
| 241 | color = vec4((0.2126 + 0.7874 * amount) * color.r + (0.7152 - 0.7152 * amount) * color.g + (0.0722 - 0.0722 * amount) * color.b, |
| 242 | (0.2126 - 0.2126 * amount) * color.r + (0.7152 + 0.2848 * amount) * color.g + (0.0722 - 0.0722 * amount) * color.b, |
| 243 | (0.2126 - 0.2126 * amount) * color.r + (0.7152 - 0.7152 * amount) * color.g + (0.0722 + 0.9278 * amount) * color.b, |
| 244 | color.a); |
| 245 | } |
| 246 | |
| 247 | void applySepiaFilter(inout vec4 color) |
| 248 | { |
| 249 | float amount = 1.0 - u_filterAmount; |
| 250 | color = vec4((0.393 + 0.607 * amount) * color.r + (0.769 - 0.769 * amount) * color.g + (0.189 - 0.189 * amount) * color.b, |
| 251 | (0.349 - 0.349 * amount) * color.r + (0.686 + 0.314 * amount) * color.g + (0.168 - 0.168 * amount) * color.b, |
| 252 | (0.272 - 0.272 * amount) * color.r + (0.534 - 0.534 * amount) * color.g + (0.131 + 0.869 * amount) * color.b, |
| 253 | color.a); |
| 254 | } |
| 255 | |
| 256 | void applySaturateFilter(inout vec4 color) |
| 257 | { |
| 258 | 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, |
| 259 | (0.213 - 0.213 * u_filterAmount) * color.r + (0.715 + 0.285 * u_filterAmount) * color.g + (0.072 - 0.072 * u_filterAmount) * color.b, |
| 260 | (0.213 - 0.213 * u_filterAmount) * color.r + (0.715 - 0.715 * u_filterAmount) * color.g + (0.072 + 0.928 * u_filterAmount) * color.b, |
| 261 | color.a); |
| 262 | } |
| 263 | |
| 264 | void applyHueRotateFilter(inout vec4 color) |
| 265 | { |
| 266 | float pi = 3.14159265358979323846; |
| 267 | float c = cos(u_filterAmount * pi / 180.0); |
| 268 | float s = sin(u_filterAmount * pi / 180.0); |
| 269 | 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), |
| 270 | 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), |
| 271 | 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), |
| 272 | color.a); |
| 273 | } |
| 274 | |
| 275 | float invert(float n) { return (1.0 - n) * u_filterAmount + n * (1.0 - u_filterAmount); } |
| 276 | void applyInvertFilter(inout vec4 color) |
| 277 | { |
| 278 | color = vec4(invert(color.r), invert(color.g), invert(color.b), color.a); |
| 279 | } |
| 280 | |
| 281 | void applyBrightnessFilter(inout vec4 color) |
| 282 | { |
| 283 | color = vec4(color.rgb * u_filterAmount, color.a); |
| 284 | } |
| 285 | |
| 286 | float contrast(float n) { return (n - 0.5) * u_filterAmount + 0.5; } |
| 287 | void applyContrastFilter(inout vec4 color) |
| 288 | { |
| 289 | color = vec4(contrast(color.r), contrast(color.g), contrast(color.b), color.a); |
| 290 | } |
| 291 | |
| 292 | void applyOpacityFilter(inout vec4 color) |
| 293 | { |
| 294 | color = vec4(color.r, color.g, color.b, color.a * u_filterAmount); |
| 295 | } |
| 296 | |
| 297 | vec4 sampleColorAtRadius(float radius, vec2 texCoord) |
| 298 | { |
| 299 | vec2 coord = texCoord + radius * u_blurRadius; |
| 300 | return SamplerFunction(s_sampler, coord) * float(coord.x > 0. && coord.y > 0. && coord.x < 1. && coord.y < 1.); |
| 301 | } |
| 302 | |
| 303 | float sampleAlphaAtRadius(float radius, vec2 texCoord) |
| 304 | { |
| 305 | vec2 coord = texCoord - u_shadowOffset + radius * u_blurRadius; |
| 306 | return SamplerFunction(s_sampler, coord).a * float(coord.x > 0. && coord.y > 0. && coord.x < 1. && coord.y < 1.); |
| 307 | } |
| 308 | |
| 309 | void applyBlurFilter(inout vec4 color, vec2 texCoord) |
| 310 | { |
| 311 | vec4 total = sampleColorAtRadius(0., texCoord) * u_gaussianKernel[0]; |
| 312 | for (int i = 1; i < GAUSSIAN_KERNEL_HALF_WIDTH; i++) { |
| 313 | total += sampleColorAtRadius(float(i) * GAUSSIAN_KERNEL_STEP, texCoord) * u_gaussianKernel[i]; |
| 314 | total += sampleColorAtRadius(float(-1 * i) * GAUSSIAN_KERNEL_STEP, texCoord) * u_gaussianKernel[i]; |
| 315 | } |
| 316 | |
| 317 | color = total; |
| 318 | } |
| 319 | |
| 320 | void applyAlphaBlur(inout vec4 color, vec2 texCoord) |
| 321 | { |
| 322 | float total = sampleAlphaAtRadius(0., texCoord) * u_gaussianKernel[0]; |
| 323 | for (int i = 1; i < GAUSSIAN_KERNEL_HALF_WIDTH; i++) { |
| 324 | total += sampleAlphaAtRadius(float(i) * GAUSSIAN_KERNEL_STEP, texCoord) * u_gaussianKernel[i]; |
| 325 | total += sampleAlphaAtRadius(float(-1 * i) * GAUSSIAN_KERNEL_STEP, texCoord) * u_gaussianKernel[i]; |
| 326 | } |
| 327 | |
| 328 | color *= total; |
| 329 | } |
| 330 | |
| 331 | vec4 sourceOver(vec4 src, vec4 dst) { return src + dst * (1. - dst.a); } |
| 332 | |
| 333 | void applyContentTexture(inout vec4 color, vec2 texCoord) |
| 334 | { |
| 335 | vec4 contentColor = texture2D(s_contentTexture, texCoord); |
| 336 | color = sourceOver(contentColor, color); |
| 337 | } |
| 338 | |
| 339 | void applySolidColor(inout vec4 color) { color *= u_color; } |
| 340 | |
| 341 | void main(void) |
| 342 | { |
| 343 | vec4 color = vec4(1., 1., 1., 1.); |
| 344 | vec2 texCoord = transformTexCoord(); |
| 345 | applyManualRepeatIfNeeded(texCoord); |
| 346 | applyTextureIfNeeded(color, texCoord); |
| 347 | applySolidColorIfNeeded(color); |
| 348 | applyAntialiasingIfNeeded(color); |
| 349 | applyOpacityIfNeeded(color); |
| 350 | applyGrayscaleFilterIfNeeded(color); |
| 351 | applySepiaFilterIfNeeded(color); |
| 352 | applySaturateFilterIfNeeded(color); |
| 353 | applyHueRotateFilterIfNeeded(color); |
| 354 | applyInvertFilterIfNeeded(color); |
| 355 | applyBrightnessFilterIfNeeded(color); |
| 356 | applyContrastFilterIfNeeded(color); |
| 357 | applyOpacityFilterIfNeeded(color); |
| 358 | applyBlurFilterIfNeeded(color, texCoord); |
| 359 | applyAlphaBlurIfNeeded(color, texCoord); |
| 360 | applyContentTextureIfNeeded(color, texCoord); |
| 361 | gl_FragColor = color; |
| 362 | } |
| 363 | ); |
| 364 | |
| 365 | Ref<TextureMapperShaderProgram> TextureMapperShaderProgram::create(TextureMapperShaderProgram::Options options) |
| 366 | { |
| 367 | #define SET_APPLIER_FROM_OPTIONS(Applier) \ |
| 368 | optionsApplierBuilder.append(\ |
| 369 | (options & TextureMapperShaderProgram::Applier) ? ENABLE_APPLIER(Applier) : DISABLE_APPLIER(Applier)) |
| 370 | |
| 371 | StringBuilder optionsApplierBuilder; |
| 372 | SET_APPLIER_FROM_OPTIONS(Texture); |
| 373 | SET_APPLIER_FROM_OPTIONS(Rect); |
| 374 | SET_APPLIER_FROM_OPTIONS(SolidColor); |
| 375 | SET_APPLIER_FROM_OPTIONS(Opacity); |
| 376 | SET_APPLIER_FROM_OPTIONS(Antialiasing); |
| 377 | SET_APPLIER_FROM_OPTIONS(GrayscaleFilter); |
| 378 | SET_APPLIER_FROM_OPTIONS(SepiaFilter); |
| 379 | SET_APPLIER_FROM_OPTIONS(SaturateFilter); |
| 380 | SET_APPLIER_FROM_OPTIONS(HueRotateFilter); |
| 381 | SET_APPLIER_FROM_OPTIONS(BrightnessFilter); |
| 382 | SET_APPLIER_FROM_OPTIONS(ContrastFilter); |
| 383 | SET_APPLIER_FROM_OPTIONS(InvertFilter); |
| 384 | SET_APPLIER_FROM_OPTIONS(OpacityFilter); |
| 385 | SET_APPLIER_FROM_OPTIONS(BlurFilter); |
| 386 | SET_APPLIER_FROM_OPTIONS(AlphaBlur); |
| 387 | SET_APPLIER_FROM_OPTIONS(ContentTexture); |
| 388 | SET_APPLIER_FROM_OPTIONS(ManualRepeat); |
| 389 | |
| 390 | StringBuilder vertexShaderBuilder; |
| 391 | |
| 392 | // OpenGL >= 3.2 requires a #version directive at the beginning of the code. |
| 393 | #if !USE(OPENGL_ES) |
| 394 | unsigned glVersion = GLContext::current()->version(); |
| 395 | if (glVersion >= 320) |
| 396 | vertexShaderBuilder.append(GLSL_DIRECTIVE(version 150)); |
| 397 | #endif |
| 398 | |
| 399 | // Append the options. |
| 400 | vertexShaderBuilder.append(optionsApplierBuilder.toString()); |
| 401 | |
| 402 | // Append the appropriate input/output variable definitions. |
| 403 | #if USE(OPENGL_ES) |
| 404 | vertexShaderBuilder.append(vertexTemplateLT320Vars); |
| 405 | #else |
| 406 | if (glVersion >= 320) |
| 407 | vertexShaderBuilder.append(vertexTemplateGE320Vars); |
| 408 | else |
| 409 | vertexShaderBuilder.append(vertexTemplateLT320Vars); |
| 410 | #endif |
| 411 | |
| 412 | // Append the common code. |
| 413 | vertexShaderBuilder.append(vertexTemplateCommon); |
| 414 | |
| 415 | StringBuilder fragmentShaderBuilder; |
| 416 | |
| 417 | // OpenGL >= 3.2 requires a #version directive at the beginning of the code. |
| 418 | #if !USE(OPENGL_ES) |
| 419 | if (glVersion >= 320) |
| 420 | fragmentShaderBuilder.append(GLSL_DIRECTIVE(version 150)); |
| 421 | #endif |
| 422 | |
| 423 | // Append the options. |
| 424 | fragmentShaderBuilder.append(optionsApplierBuilder.toString()); |
| 425 | |
| 426 | // Append the common header. |
| 427 | fragmentShaderBuilder.append(fragmentTemplateHeaderCommon); |
| 428 | |
| 429 | // Append the appropriate input/output variable definitions. |
| 430 | #if USE(OPENGL_ES) |
| 431 | fragmentShaderBuilder.append(fragmentTemplateLT320Vars); |
| 432 | #else |
| 433 | if (glVersion >= 320) |
| 434 | fragmentShaderBuilder.append(fragmentTemplateGE320Vars); |
| 435 | else |
| 436 | fragmentShaderBuilder.append(fragmentTemplateLT320Vars); |
| 437 | #endif |
| 438 | |
| 439 | // Append the common code. |
| 440 | fragmentShaderBuilder.append(fragmentTemplateCommon); |
| 441 | |
| 442 | return adoptRef(*new TextureMapperShaderProgram(vertexShaderBuilder.toString(), fragmentShaderBuilder.toString())); |
| 443 | } |
| 444 | |
| 445 | #if !LOG_DISABLED |
| 446 | static CString getShaderLog(GLuint shader) |
| 447 | { |
| 448 | GLint logLength = 0; |
| 449 | glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength); |
| 450 | if (!logLength) |
| 451 | return { }; |
| 452 | |
| 453 | Vector<GLchar> info(logLength); |
| 454 | GLsizei infoLength = 0; |
| 455 | glGetShaderInfoLog(shader, logLength, &infoLength, info.data()); |
| 456 | |
| 457 | size_t stringLength = std::max(infoLength, 0); |
| 458 | return { info.data(), stringLength }; |
| 459 | } |
| 460 | |
| 461 | static CString getProgramLog(GLuint program) |
| 462 | { |
| 463 | GLint logLength = 0; |
| 464 | glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength); |
| 465 | if (!logLength) |
| 466 | return { }; |
| 467 | |
| 468 | Vector<GLchar> info(logLength); |
| 469 | GLsizei infoLength = 0; |
| 470 | glGetProgramInfoLog(program, logLength, &infoLength, info.data()); |
| 471 | |
| 472 | size_t stringLength = std::max(infoLength, 0); |
| 473 | return { info.data(), stringLength }; |
| 474 | } |
| 475 | #endif |
| 476 | |
| 477 | TextureMapperShaderProgram::TextureMapperShaderProgram(const String& vertex, const String& fragment) |
| 478 | { |
| 479 | m_vertexShader = glCreateShader(GL_VERTEX_SHADER); |
| 480 | { |
| 481 | CString vertexCString = vertex.utf8(); |
| 482 | const char* data = vertexCString.data(); |
| 483 | int length = vertexCString.length(); |
| 484 | glShaderSource(m_vertexShader, 1, &data, &length); |
| 485 | } |
| 486 | glCompileShader(m_vertexShader); |
| 487 | |
| 488 | m_fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); |
| 489 | { |
| 490 | CString fragmentCString = fragment.utf8(); |
| 491 | const char* data = fragmentCString.data(); |
| 492 | int length = fragmentCString.length(); |
| 493 | glShaderSource(m_fragmentShader, 1, &data, &length); |
| 494 | } |
| 495 | glCompileShader(m_fragmentShader); |
| 496 | |
| 497 | m_id = glCreateProgram(); |
| 498 | glAttachShader(m_id, m_vertexShader); |
| 499 | glAttachShader(m_id, m_fragmentShader); |
| 500 | glLinkProgram(m_id); |
| 501 | |
| 502 | if (!compositingLogEnabled() || glGetError() == GL_NO_ERROR) |
| 503 | return; |
| 504 | |
| 505 | LOG(Compositing, "Vertex shader log: %s\n" , getShaderLog(m_vertexShader).data()); |
| 506 | LOG(Compositing, "Fragment shader log: %s\n" , getShaderLog(m_fragmentShader).data()); |
| 507 | LOG(Compositing, "Program log: %s\n" , getProgramLog(m_id).data()); |
| 508 | } |
| 509 | |
| 510 | TextureMapperShaderProgram::~TextureMapperShaderProgram() |
| 511 | { |
| 512 | if (!m_id) |
| 513 | return; |
| 514 | |
| 515 | glDetachShader(m_id, m_vertexShader); |
| 516 | glDeleteShader(m_vertexShader); |
| 517 | glDetachShader(m_id, m_fragmentShader); |
| 518 | glDeleteShader(m_fragmentShader); |
| 519 | glDeleteProgram(m_id); |
| 520 | } |
| 521 | |
| 522 | void TextureMapperShaderProgram::setMatrix(GLuint location, const TransformationMatrix& matrix) |
| 523 | { |
| 524 | auto floatMatrix = matrix.toColumnMajorFloatArray(); |
| 525 | glUniformMatrix4fv(location, 1, false, floatMatrix.data()); |
| 526 | } |
| 527 | |
| 528 | GLuint TextureMapperShaderProgram::getLocation(const AtomicString& name, VariableType type) |
| 529 | { |
| 530 | auto addResult = m_variables.ensure(name, |
| 531 | [this, &name, type] { |
| 532 | CString nameCString = name.string().utf8(); |
| 533 | switch (type) { |
| 534 | case UniformVariable: |
| 535 | return glGetUniformLocation(m_id, nameCString.data()); |
| 536 | case AttribVariable: |
| 537 | return glGetAttribLocation(m_id, nameCString.data()); |
| 538 | } |
| 539 | ASSERT_NOT_REACHED(); |
| 540 | return 0; |
| 541 | }); |
| 542 | return addResult.iterator->value; |
| 543 | } |
| 544 | |
| 545 | } // namespace WebCore |
| 546 | |
| 547 | #endif // USE(TEXTURE_MAPPER_GL) |
| 548 | |