1/* 2 * Copyright (C) 2012, 2013 Research In Motion Limited. All rights reserved. 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19#include "config.h" 20 21#if USE(ACCELERATED_COMPOSITING) && ENABLE(CSS_FILTERS) 22 23#include "LayerFilterRenderer.h" 24 25#include "FilterOperation.h" 26#include "LayerCompositingThread.h" 27#include "LayerRenderer.h" 28#include "NotImplemented.h" 29#include "TextureCacheCompositingThread.h" 30 31#include <BlackBerryPlatformGraphics.h> 32#include <BlackBerryPlatformLog.h> 33#include <Vector.h> 34 35#include <cstring> 36#include <limits> 37#include <wtf/text/WTFString.h> 38 39namespace WebCore { 40 41class SurfaceFunctor { 42public: 43 SurfaceFunctor(LayerRendererSurface* surface) 44 : m_surface(surface) 45 { 46 } 47 48protected: 49 LayerRendererSurface* m_surface; 50}; 51 52class InverseSurfaceWidth : public SurfaceFunctor { 53public: 54 InverseSurfaceWidth(LayerRendererSurface* surface) : SurfaceFunctor(surface) { } 55 56 float operator() () { return 1.0f / m_surface->size().width(); } 57}; 58 59class InverseSurfaceHeight : public SurfaceFunctor { 60public: 61 InverseSurfaceHeight(LayerRendererSurface* surface) : SurfaceFunctor(surface) { } 62 63 float operator() () { return 1.0f / m_surface->size().height(); } 64}; 65 66static int operationTypeToProgramID(const FilterOperation::OperationType& t) 67{ 68 switch (t) { 69 case FilterOperation::GRAYSCALE: 70 return LayerData::CSSFilterShaderGrayscale; 71 case FilterOperation::SEPIA: 72 return LayerData::CSSFilterShaderSepia; 73 case FilterOperation::SATURATE: 74 return LayerData::CSSFilterShaderSaturate; 75 case FilterOperation::HUE_ROTATE: 76 return LayerData::CSSFilterShaderHueRotate; 77 case FilterOperation::INVERT: 78 return LayerData::CSSFilterShaderInvert; 79 case FilterOperation::OPACITY: 80 return LayerData::CSSFilterShaderOpacity; 81 case FilterOperation::BRIGHTNESS: 82 return LayerData::CSSFilterShaderBrightness; 83 case FilterOperation::CONTRAST: 84 return LayerData::CSSFilterShaderContrast; 85 case FilterOperation::BLUR: 86 return LayerData::CSSFilterShaderBlurY; 87 case FilterOperation::DROP_SHADOW: 88 return LayerData::CSSFilterShaderShadow; 89#if ENABLE(CSS_SHADERS) 90 case FilterOperation::CUSTOM: 91 return LayerData::CSSFilterShaderCustom; 92#endif 93 default: 94 ASSERT_NOT_REACHED(); 95 return -1; 96 } 97} 98 99Uniform::Uniform(int c_location) 100 : m_location(c_location) 101{ 102} 103 104void Uniform1f::apply() 105{ 106 glUniform1f(location(), m_val); 107} 108 109PassRefPtr<Uniform> Uniform1f::create(int location, float val) 110{ 111 return adoptRef(new Uniform1f(location, val)); 112} 113 114Uniform1f::Uniform1f(int c_location, float c_val) 115 : Uniform(c_location) 116 , m_val(c_val) 117{ 118} 119 120void Uniform1i::apply() 121{ 122 glUniform1i(location(), m_val); 123} 124 125PassRefPtr<Uniform> Uniform1i::create(int location, int val) 126{ 127 return adoptRef(new Uniform1i(location, val)); 128} 129 130Uniform1i::Uniform1i(int c_location, int c_val) 131 : Uniform(c_location) 132 , m_val(c_val) 133{ 134} 135 136void Uniform2f::apply() 137{ 138 glUniform2f(location(), m_val[0], m_val[1]); 139} 140 141PassRefPtr<Uniform> Uniform2f::create(int location, float val0, float val1) 142{ 143 return adoptRef(new Uniform2f(location, val0, val1)); 144} 145 146Uniform2f::Uniform2f(int c_location, float c_val0, float c_val1) 147 : Uniform(c_location) 148{ 149 m_val[0] = c_val0; 150 m_val[1] = c_val1; 151} 152 153void Uniform3f::apply() 154{ 155 glUniform3f(location(), m_val[0], m_val[1], m_val[2]); 156} 157 158PassRefPtr<Uniform> Uniform3f::create(int location, float val0, float val1, float val2) 159{ 160 return adoptRef(new Uniform3f(location, val0, val1, val2)); 161} 162 163Uniform3f::Uniform3f(int c_location, float c_val0, float c_val1, float c_val2) 164 : Uniform(c_location) 165{ 166 m_val[0] = c_val0; 167 m_val[1] = c_val1; 168 m_val[2] = c_val2; 169} 170 171void Uniform4f::apply() 172{ 173 glUniform4f(location(), m_val[0], m_val[1], m_val[2], m_val[3]); 174} 175 176PassRefPtr<Uniform> Uniform4f::create(int location, float val0, float val1, float val2, float val3) 177{ 178 return adoptRef(new Uniform4f(location, val0, val1, val2, val3)); 179} 180 181Uniform4f::Uniform4f(int c_location, float c_val0, float c_val1, float c_val2, float c_val3) 182 : Uniform(c_location) 183{ 184 m_val[0] = c_val0; 185 m_val[1] = c_val1; 186 m_val[2] = c_val2; 187 m_val[3] = c_val3; 188} 189 190void Matrix4fv::apply() 191{ 192 glUniformMatrix4fv(location(), m_size, m_transpose, m_array); 193} 194 195PassRefPtr<Parameter> Matrix4fv::create(GLint location, GLsizei size, GLboolean transpose, GLfloat* array) 196{ 197 return adoptRef(new Matrix4fv(location, size, transpose, array)); 198} 199 200Matrix4fv::Matrix4fv(GLint clocation, GLsizei size, GLboolean transpose, GLfloat* array) 201 : Uniform(clocation) 202 , m_size(size) 203 , m_transpose(transpose) 204 , m_array(0) 205{ 206 m_array = new GLfloat[size * 4 * 4]; 207 std::memcpy(m_array, array, size * 4 * 4 * sizeof(GLfloat)); 208} 209 210Matrix4fv::~Matrix4fv() 211{ 212 delete[] m_array; 213} 214 215void Buffer::apply() 216{ 217 glBindBuffer(m_buffer, m_object); 218} 219 220void Buffer::restoreState() 221{ 222 glBindBuffer(m_buffer, 0); 223} 224 225PassRefPtr<Parameter> Buffer::create(GLenum buffer, GLuint object) 226{ 227 return adoptRef(new Buffer(buffer, object)); 228} 229 230Buffer::Buffer(GLenum buffer, GLuint object) 231 : Parameter() 232 , m_buffer(buffer) 233 , m_object(object) 234{ 235} 236 237void VertexAttribf::apply() 238{ 239 glVertexAttribPointer(m_location, m_size, GL_FLOAT, false, m_bytesPerVertex, reinterpret_cast<GLvoid*>(static_cast<intptr_t>(m_offset))); 240 glEnableVertexAttribArray(m_location); 241} 242 243void VertexAttribf::restoreState() 244{ 245 glDisableVertexAttribArray(m_location); 246} 247 248PassRefPtr<Parameter> VertexAttribf::create(int location, int size, int bytesPerVertex, int offset) 249{ 250 return adoptRef(new VertexAttribf(location, size, bytesPerVertex, offset)); 251} 252 253 254VertexAttribf::VertexAttribf(int location, int size, int bytesPerVertex, int offset) 255 : Parameter() 256 , m_location(location) 257 , m_size(size) 258 , m_bytesPerVertex(bytesPerVertex) 259 , m_offset(offset) 260{ 261} 262 263PassRefPtr<LayerFilterRendererAction> LayerFilterRendererAction::create(int programId) 264{ 265 return adoptRef(new LayerFilterRendererAction(programId)); 266} 267 268LayerFilterRendererAction::LayerFilterRendererAction(int c_programId) 269 : m_programId(c_programId) 270 , m_pushSnapshot(false) 271 , m_popSnapshot(false) 272 , m_drawingMode(DrawTriangleFanArrays) 273{ 274} 275 276void LayerFilterRendererAction::useActionOn(LayerFilterRenderer* renderer) 277{ 278 ASSERT(m_programId != -1); 279 if (m_programId == -1) { 280 glUseProgram(renderer->m_cssFilterProgramObject[LayerData::CSSFilterShaderPassthrough]); 281 return; 282 } 283 glUseProgram(renderer->m_cssFilterProgramObject[m_programId]); 284 for (unsigned i = 0; i < m_parameters.size(); ++i) 285 m_parameters[i]->apply(); 286} 287 288void LayerFilterRendererAction::restoreState() 289{ 290 for (unsigned i = 0; i < m_parameters.size(); ++i) 291 m_parameters[i]->restoreState(); 292} 293 294PassOwnPtr<LayerFilterRenderer> LayerFilterRenderer::create(const int& positionLocation, const int& texCoordLocation) 295{ 296 return adoptPtr(new LayerFilterRenderer(positionLocation, texCoordLocation)); 297} 298 299LayerFilterRenderer::LayerFilterRenderer(const int& positionLocation, const int& texCoordLocation) 300 : m_positionLocation(positionLocation) 301 , m_texCoordLocation(texCoordLocation) 302{ 303 // If you ever move this stuff, please make sure that 304 // everything in this constructor is called BEFORE actionsForOperations. 305 306 for (int i = 0; i < LayerData::NumberOfCSSFilterShaders; ++i) 307 m_cssFilterProgramObject[i] = 0; 308 309 if (!(m_enabled = initializeSharedGLObjects())) 310 BlackBerry::Platform::logAlways(BlackBerry::Platform::LogLevelWarn, "CSS Filters are not enabled due to failed initialization."); 311} 312 313// Binds the given attribute name to a common location across all programs 314// used by the compositor. This allows the code to bind the attributes only once 315// even when switching between programs. 316// 317// This is an extension of LayerRenderer::bindCommonAttribLocation and the locations 318// will match those of LayerRenderer. See LayerFilterRenderer::LayerFilterRenderer() 319void LayerFilterRenderer::bindCommonAttribLocation(int location, const char* attribName) 320{ 321 for (int i = 0; i < LayerData::NumberOfCSSFilterShaders; ++i) 322 glBindAttribLocation(m_cssFilterProgramObject[i], location, attribName); 323} 324 325bool LayerFilterRenderer::initializeSharedGLObjects() 326{ 327 // See also TextureMapperShaderManager.cpp 328 329 char standardVertexShaderString[] = 330 "attribute vec4 a_position; \n" 331 "attribute vec2 a_texCoord; \n" 332 "varying vec2 v_texCoord; \n" 333 "void main() \n" 334 "{ \n" 335 " gl_Position = a_position; \n" 336 " v_texCoord = a_texCoord; \n" 337 "} \n"; 338 339 char offsetVertexShaderString[] = 340 "attribute vec4 a_position; \n" 341 "attribute vec2 a_texCoord; \n" 342 "uniform mediump vec2 u_offset; \n" 343 "varying vec2 v_texCoord; \n" 344 "void main() \n" 345 "{ \n" 346 " gl_Position = a_position; \n" 347 " v_texCoord = a_texCoord - u_offset; \n" 348 "} \n"; 349 350#define STANDARD_FILTER(x...) \ 351 "precision mediump float; \n"\ 352 "\n"\ 353 "varying mediump vec2 v_texCoord;\n"\ 354 "uniform lowp sampler2D s_texture;\n"\ 355 "uniform highp float u_amount;\n"\ 356#x\ 357 "void main(void)\n { gl_FragColor = shade(texture2D(s_texture, v_texCoord)); }" 358 359#define BLUR_FILTER(x...) \ 360 "precision highp float; \n"\ 361 "\n"\ 362 "varying mediump vec2 v_texCoord;\n"\ 363 "uniform lowp sampler2D s_texture;\n"\ 364 "uniform highp float u_amount;\n"\ 365 "uniform highp float u_blurSize;\n"\ 366 "const float pi = 3.1415927;\n"\ 367#x\ 368 "void main(void)\n"\ 369 "{\n"\ 370 "vec3 incr;\n"\ 371 "incr.x = 1.0 / (sqrt(2.0 * pi) * u_amount);\n"\ 372 "incr.y = exp(-0.5 / (u_amount * u_amount));\n"\ 373 "incr.z = incr.y * incr.y;\n"\ 374 "\n"\ 375 "vec4 avg = vec4(0.0, 0.0, 0.0, 0.0);\n"\ 376 "float coefficientSum = 0.0;\n"\ 377 "\n"\ 378 "avg += texture2D(s_texture, v_texCoord.xy) * incr.x;\n"\ 379 "coefficientSum += incr.x;\n"\ 380 "incr.xy *= incr.yz;\n"\ 381 "\n"\ 382 "for (float i = 1.0; i <= u_amount; i++) {\n"\ 383 " avg += texture2D(s_texture, v_texCoord.xy - i * u_blurSize * blurMultiplyVec) * incr.x;\n"\ 384 " avg += texture2D(s_texture, v_texCoord.xy + i * u_blurSize * blurMultiplyVec) * incr.x;\n"\ 385 " coefficientSum += 2.0 * incr.x;\n"\ 386 " incr.xy *= incr.yz;\n"\ 387 "}\n"\ 388 "\n"\ 389 "gl_FragColor = avg / coefficientSum;\n"\ 390 "}" 391 392 const char* shaderStrs[LayerData::NumberOfCSSFilterShaders]; 393 394 shaderStrs[LayerData::CSSFilterShaderGrayscale] = STANDARD_FILTER( 395 lowp vec4 shade(lowp vec4 color) 396 { 397 lowp float amount = 1.0 - u_amount; 398 return vec4((0.2126 + 0.7874 * amount) * color.r + (0.7152 - 0.7152 * amount) * color.g + (0.0722 - 0.0722 * amount) * color.b, 399 (0.2126 - 0.2126 * amount) * color.r + (0.7152 + 0.2848 * amount) * color.g + (0.0722 - 0.0722 * amount) * color.b, 400 (0.2126 - 0.2126 * amount) * color.r + (0.7152 - 0.7152 * amount) * color.g + (0.0722 + 0.9278 * amount) * color.b, 401 color.a); 402 } 403 ); 404 405 shaderStrs[LayerData::CSSFilterShaderSepia] = STANDARD_FILTER( 406 lowp vec4 shade(lowp vec4 color) 407 { 408 lowp float amount = 1.0 - u_amount; 409 return vec4((0.393 + 0.607 * amount) * color.r + (0.769 - 0.769 * amount) * color.g + (0.189 - 0.189 * amount) * color.b, 410 (0.349 - 0.349 * amount) * color.r + (0.686 + 0.314 * amount) * color.g + (0.168 - 0.168 * amount) * color.b, 411 (0.272 - 0.272 * amount) * color.r + (0.534 - 0.534 * amount) * color.g + (0.131 + 0.869 * amount) * color.b, 412 color.a); 413 } 414 ); 415 416 shaderStrs[LayerData::CSSFilterShaderSaturate] = STANDARD_FILTER( 417 lowp vec4 shade(lowp vec4 color) 418 { 419 return vec4((0.213 + 0.787 * u_amount) * color.r + (0.715 - 0.715 * u_amount) * color.g + (0.072 - 0.072 * u_amount) * color.b, 420 (0.213 - 0.213 * u_amount) * color.r + (0.715 + 0.285 * u_amount) * color.g + (0.072 - 0.072 * u_amount) * color.b, 421 (0.213 - 0.213 * u_amount) * color.r + (0.715 - 0.715 * u_amount) * color.g + (0.072 + 0.928 * u_amount) * color.b, 422 color.a); 423 } 424 ); 425 426 shaderStrs[LayerData::CSSFilterShaderHueRotate] = STANDARD_FILTER( 427 lowp vec4 shade(lowp vec4 color) 428 { 429 highp float pi = 3.14159265358979323846; 430 highp float c = cos(u_amount * pi / 180.0); 431 highp float s = sin(u_amount * pi / 180.0); 432 return 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), 433 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), 434 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), 435 color.a); 436 } 437 ); 438 439 shaderStrs[LayerData::CSSFilterShaderInvert] = STANDARD_FILTER( 440 lowp float invert(lowp float n) { return (1.0 - n) * u_amount + n * (1.0 - u_amount); } 441 lowp vec4 shade(lowp vec4 color) 442 { 443 return vec4(invert(color.r), invert(color.g), invert(color.b), color.a); 444 } 445 ); 446 447 shaderStrs[LayerData::CSSFilterShaderBrightness] = STANDARD_FILTER( 448 lowp vec4 shade(lowp vec4 color) 449 { 450 return vec4(color.rgb * (1.0 + u_amount), color.a); 451 } 452 ); 453 454 shaderStrs[LayerData::CSSFilterShaderContrast] = STANDARD_FILTER( 455 lowp float contrast(lowp float n) { return (n - 0.5) * u_amount + 0.5; } 456 lowp vec4 shade(lowp vec4 color) 457 { 458 return vec4(contrast(color.r), contrast(color.g), contrast(color.b), color.a); 459 } 460 ); 461 462 shaderStrs[LayerData::CSSFilterShaderOpacity] = STANDARD_FILTER( 463 lowp vec4 shade(lowp vec4 color) 464 { 465 return vec4(color.r, color.g, color.b, color.a * u_amount); 466 } 467 ); 468 469 shaderStrs[LayerData::CSSFilterShaderBlurX] = BLUR_FILTER( 470 const vec2 blurMultiplyVec = vec2(1.0, 0.0); 471 ); 472 473 shaderStrs[LayerData::CSSFilterShaderBlurY] = BLUR_FILTER( 474 const vec2 blurMultiplyVec = vec2(0.0, 1.0); 475 ); 476 477 shaderStrs[LayerData::CSSFilterShaderShadow] = STANDARD_FILTER( 478 uniform lowp vec3 u_color; 479 lowp vec4 shade(lowp vec4 color) 480 { 481 if (color.a > 0.5) 482 return vec4(u_color.r, u_color.g, u_color.b, color.a); 483 return color; 484 } 485 ); 486 487 shaderStrs[LayerData::CSSFilterShaderPassthrough] = STANDARD_FILTER( 488 lowp vec4 shade(lowp vec4 color) 489 { 490 return color; 491 } 492 ); 493 494 for (int i = 0; i < LayerData::NumberOfCSSFilterShaders; i++) { 495 if (i == LayerData::CSSFilterShaderShadow) 496 m_cssFilterProgramObject[i] = LayerRenderer::loadShaderProgram(offsetVertexShaderString, shaderStrs[i]); 497 else 498 m_cssFilterProgramObject[i] = LayerRenderer::loadShaderProgram(standardVertexShaderString, shaderStrs[i]); 499 if (!m_cssFilterProgramObject[i]) { 500 BlackBerry::Platform::logAlways(BlackBerry::Platform::LogLevelWarn, "Could not load CSS Filter Shader %i", i); 501 return false; 502 } 503 } 504 505 // Set ATTRIB locations - these will be the same as the programs in LayerRenderer.cpp 506 bindCommonAttribLocation(m_positionLocation, "a_position"); 507 bindCommonAttribLocation(m_texCoordLocation, "a_texCoord"); 508 509 // Re-link to take effect 510 for (int i = 0; i < LayerData::NumberOfCSSFilterShaders; ++i) 511 glLinkProgram(m_cssFilterProgramObject[i]); 512 513 // Get UNIFORM locations 514 for (int i = 0; i < LayerData::NumberOfCSSFilterShaders; ++i) 515 m_amountLocation[i] = glGetUniformLocation(m_cssFilterProgramObject[i], "u_amount"); 516 517 m_blurAmountLocation[0] = glGetUniformLocation(m_cssFilterProgramObject[LayerData::CSSFilterShaderBlurY], "u_blurSize"); 518 m_blurAmountLocation[1] = glGetUniformLocation(m_cssFilterProgramObject[LayerData::CSSFilterShaderBlurX], "u_blurSize"); 519 520 m_shadowColorLocation = glGetUniformLocation(m_cssFilterProgramObject[LayerData::CSSFilterShaderShadow], "u_color"); 521 m_offsetLocation = glGetUniformLocation(m_cssFilterProgramObject[LayerData::CSSFilterShaderShadow], "u_offset"); 522 523 return true; 524} 525 526void LayerFilterRenderer::ping(LayerRendererSurface* surface) 527{ 528 GLuint texid = m_texture->platformTexture(); 529 530 glFramebufferTexture2D( 531 GL_FRAMEBUFFER, 532 GL_COLOR_ATTACHMENT0, 533 GL_TEXTURE_2D, 534 texid, 535 0 536 ); 537 glBindTexture( 538 GL_TEXTURE_2D, 539 surface->texture()->platformTexture() 540 ); 541} 542 543void LayerFilterRenderer::pong(LayerRendererSurface* surface) 544{ 545 glFramebufferTexture2D( 546 GL_FRAMEBUFFER, 547 GL_COLOR_ATTACHMENT0, 548 GL_TEXTURE_2D, 549 surface->texture()->platformTexture(), 550 0 551 ); 552 glBindTexture( 553 GL_TEXTURE_2D, 554 m_texture->platformTexture() 555 ); 556} 557 558void LayerFilterRenderer::pushSnapshot(LayerRendererSurface* surface, int sourceId) 559{ 560 GLuint texid = m_snapshotTexture->platformTexture(); 561 562 glFramebufferTexture2D( 563 GL_FRAMEBUFFER, 564 GL_COLOR_ATTACHMENT0, 565 GL_TEXTURE_2D, 566 texid, 567 0 568 ); 569 570 glBindTexture(GL_TEXTURE_2D, sourceId); 571 glClear(GL_COLOR_BUFFER_BIT); // to transparency 572 573 glViewport(0, 0, surface->size().width(), surface->size().height()); 574 575 glUseProgram(m_cssFilterProgramObject[LayerData::CSSFilterShaderPassthrough]); 576 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 577} 578 579void LayerFilterRenderer::popSnapshot() 580{ 581 // The name is slightly misleading. 582 // This DRAWS the previous texture using the current LayerFilterRendererAction, then sets the texture 583 // to the snapshot texture. Next time glDrawArrays is called, the snapshot will be drawn. 584 585 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 586 glBindTexture( 587 GL_TEXTURE_2D, 588 m_snapshotTexture->platformTexture() 589 ); 590} 591 592Vector<RefPtr<LayerFilterRendererAction> > LayerFilterRenderer::actionsForOperations(LayerRendererSurface* surface, const Vector<RefPtr<FilterOperation> >& ops) 593{ 594 Vector<RefPtr<LayerFilterRendererAction> > ret; 595 for (unsigned i = 0; i < ops.size(); ++i) { 596 const FilterOperation& operation = *ops[i].get(); 597 if (operation.getOperationType() == FilterOperation::BLUR && static_cast<const BlurFilterOperation&>(operation).stdDeviation().value() < 0.1) 598 continue; 599 600 int programId = operationTypeToProgramID(operation.getOperationType()); 601 ret.append(LayerFilterRendererAction::create(programId)); 602 603 switch (operation.getOperationType()) { 604 case FilterOperation::GRAYSCALE: 605 case FilterOperation::SEPIA: 606 case FilterOperation::SATURATE: 607 case FilterOperation::HUE_ROTATE: 608 ret.last()->appendParameter(Uniform1f::create(m_amountLocation[programId] 609 , static_cast<const BasicColorMatrixFilterOperation&>(operation).amount())); 610 break; 611 case FilterOperation::INVERT: 612 case FilterOperation::BRIGHTNESS: 613 case FilterOperation::CONTRAST: 614 case FilterOperation::OPACITY: 615 ret.last()->appendParameter(Uniform1f::create(m_amountLocation[programId] 616 , static_cast<const BasicComponentTransferFilterOperation&>(operation).amount())); 617 break; 618 case FilterOperation::BLUR: 619 { 620 // Blur is a two-step process: 621 // 1. blur X 622 // 2. blur Y 623 // This way we can have 2n time instead of n^2 time) 624 625 double amount = static_cast<const BlurFilterOperation&>(operation).stdDeviation().value(); 626 627 // BLUR Y: 628 ret.last()->appendParameter(Uniform1f::create(m_amountLocation[LayerData::CSSFilterShaderBlurY], amount)); 629 ret.last()->appendParameter(Uniform1f::createWithFunctor(m_blurAmountLocation[0], InverseSurfaceHeight(surface))); 630 631 // BLUR X: 632 ret.append(LayerFilterRendererAction::create(LayerData::CSSFilterShaderBlurX)); 633 ret.last()->appendParameter(Uniform1f::create(m_amountLocation[LayerData::CSSFilterShaderBlurX], amount)); 634 ret.last()->appendParameter(Uniform1f::createWithFunctor(m_blurAmountLocation[1], InverseSurfaceWidth(surface))); 635 636 } 637 break; 638 case FilterOperation::DROP_SHADOW: 639 { 640 // Shadow is a four-step process: 641 // 1. capture snapshot 642 // turn into a solid offset mask 643 // 2. blur X 644 // 3. blur Y 645 // 4. repaint original on top of mask 646 const DropShadowFilterOperation& dsfo = static_cast<const DropShadowFilterOperation&>(operation); 647 ret.last()->setPushSnapshot(); 648 ret.last()->appendParameter(Uniform2f::create(m_offsetLocation 649 , float(dsfo.x()) / float(surface->size().width()) 650 , float(dsfo.y()) / float(surface->size().height()))); 651 ret.last()->appendParameter(Uniform3f::create(m_shadowColorLocation 652 , float(dsfo.color().red()) / 255.0f 653 , float(dsfo.color().green()) / 255.0f 654 , float(dsfo.color().blue()) / 255.0f)); 655 656 // BLUR Y 657 ret.append(LayerFilterRendererAction::create(LayerData::CSSFilterShaderBlurY)); 658 ret.last()->appendParameter(Uniform1f::create(m_amountLocation[LayerData::CSSFilterShaderBlurY] 659 , dsfo.stdDeviation())); 660 ret.last()->appendParameter(Uniform1f::createWithFunctor(m_blurAmountLocation[0], InverseSurfaceHeight(surface))); 661 662 // BLUR X 663 ret.append(LayerFilterRendererAction::create(LayerData::CSSFilterShaderBlurX)); 664 ret.last()->appendParameter(Uniform1f::create(m_amountLocation[LayerData::CSSFilterShaderBlurX] 665 , dsfo.stdDeviation())); 666 ret.last()->appendParameter(Uniform1f::createWithFunctor(m_blurAmountLocation[1], InverseSurfaceWidth(surface))); 667 668 // Repaint original image 669 ret.append(LayerFilterRendererAction::create(LayerData::CSSFilterShaderPassthrough)); 670 ret.last()->setPopSnapshot(); 671 } 672 break; 673 default: 674 ASSERT_NOT_REACHED(); 675 break; 676 } 677 } 678 679 if (ret.size() % 2) // We need an even number of actions. See ping-pong note in applyLayerFilters(). 680 ret.append(LayerFilterRendererAction::create(LayerData::CSSFilterShaderPassthrough)); 681 682 return ret; 683} 684 685void LayerFilterRenderer::applyActions(unsigned& fbo, LayerCompositingThread* layer, Vector<RefPtr<LayerFilterRendererAction> > actions) 686{ 687 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 688 ASSERT(!(actions.size() % 2)); // See ping-ponging note below. 689 690 if (!m_enabled) 691 return; 692 693 if (!layer->filters().size()) 694 return; 695 696 if (!m_texture) 697 m_texture = textureCacheCompositingThread()->createTexture(); 698 699 bool requireSnapshot = false; 700 for (unsigned i = 0; i < actions.size(); ++i) { 701 if (actions[i]->shouldPushSnapshot()) 702 requireSnapshot = true; 703 } 704 705 if (!m_snapshotTexture && requireSnapshot) 706 m_snapshotTexture = textureCacheCompositingThread()->createTexture(); 707 708 LayerRendererSurface* surface = layer->layerRendererSurface(); 709 710 // From the code in LayerRenderer, we see that the layer will have a trivial transform that will 711 // result in the transformed bounds being a polygon with 4 vertices, i.e. a quad. 712 // The LayerFilterRenderer depends on the layer being a quad, so assert to make sure. 713 ASSERT(layer->transformedBounds().size() == 4); 714 if (layer->transformedBounds().size() != 4) 715 return; 716 717 glVertexAttribPointer(m_positionLocation, 2, GL_FLOAT, GL_FALSE, 0, layer->transformedBounds().data()); 718 glEnableVertexAttribArray(m_positionLocation); 719 glVertexAttribPointer(m_texCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, layer->textureCoordinates().data()); 720 glEnableVertexAttribArray(m_texCoordLocation); 721 722 m_texture->protect(surface->texture()->size(), BlackBerry::Platform::Graphics::AlwaysBacked); 723 if (requireSnapshot) 724 m_snapshotTexture->protect(surface->texture()->size(), BlackBerry::Platform::Graphics::AlwaysBacked); 725 726 if (!fbo) 727 glGenFramebuffers(1, &fbo); 728 729 glBindFramebuffer(GL_FRAMEBUFFER, fbo); 730 731 for (unsigned i = 0; i < actions.size(); ++i) { 732 // NOTE ABOUT PING-PONGING 733 // ======================= 734 // Under OpenGL ES 2.0, we cannot use the fbo we are writting to as a texture, so we need to play ping-pong: 735 // 1) Draw parent surface to our texture with effect. 736 // 2) Draw our surface to parent texture with effect. 737 // 3) Repeat. 738 // Because we eventually have to end on the parent texture, we need an even number of actions. 739 // actionsForOperations takes care of that. 740 741 if (actions[i]->shouldPushSnapshot()) { 742 RefPtr<LayerTexture> currentTexture = (!(i % 2) ? surface->texture() : m_texture); 743 pushSnapshot(surface, currentTexture->platformTexture()); 744 } 745 if (!(i % 2)) 746 ping(surface); // Set framebuffer to ours, and texture to parent 747 else 748 pong(surface); // Set texture to parent, and framebuffer to us 749 750 glClear(GL_COLOR_BUFFER_BIT); // to transparency 751 glViewport(0, 0, surface->size().width(), surface->size().height()); 752 753 actions[i]->useActionOn(this); 754 755 if (actions[i]->shouldPopSnapshot()) 756 popSnapshot(); 757 758 switch (actions[i]->drawingMode()) { 759 case LayerFilterRendererAction::DrawTriangleFanArrays: 760 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 761 break; 762 case LayerFilterRendererAction::DrawTriangleElementsUShort0: 763 glDrawElements(GL_TRIANGLES, actions[i]->drawingModeParameter(), GL_UNSIGNED_SHORT, reinterpret_cast<GLvoid*>(static_cast<intptr_t>(0))); 764 break; 765 case LayerFilterRendererAction::NumberOfDrawingModes: 766 ASSERT_NOT_REACHED(); 767 break; 768 } 769 770 actions[i]->restoreState(); 771 772 glVertexAttribPointer(m_positionLocation, 2, GL_FLOAT, GL_FALSE, 0, layer->transformedBounds().data()); 773 glEnableVertexAttribArray(m_positionLocation); 774 glVertexAttribPointer(m_texCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, layer->textureCoordinates().data()); 775 glEnableVertexAttribArray(m_texCoordLocation); 776 } 777 778 m_texture->unprotect(); 779 if (requireSnapshot) 780 m_snapshotTexture->unprotect(); 781 glBindTexture(GL_TEXTURE_2D, 0); 782 783 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 784} 785 786} // namespace WebCore 787 788#endif // USE(ACCELERATED_COMPOSITING) && USE(CSS_FILTERS) 789