1 /* 2 * Copyright 2010, The Android Open Source Project 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #define LOG_TAG "ShaderProgram" 27 #define LOG_NDEBUG 1 28 29 #include "config.h" 30 #include "ShaderProgram.h" 31 32 #if USE(ACCELERATED_COMPOSITING) 33 34 #include "AndroidLog.h" 35 #include "DrawQuadData.h" 36 #include "FloatPoint3D.h" 37 #include "GLUtils.h" 38 #include "TilesManager.h" 39 40 #include <GLES2/gl2.h> 41 #include <GLES2/gl2ext.h> 42 43 #define EPSILON 0.00001f 44 45 namespace WebCore { 46 47 // fillPortion.xy = starting UV coordinates. 48 // fillPortion.zw = UV coordinates width and height. 49 static const char gVertexShader[] = 50 "attribute vec4 vPosition;\n" 51 "uniform mat4 projectionMatrix;\n" 52 "uniform vec4 fillPortion;\n" 53 "varying vec2 v_texCoord;\n" 54 "void main() {\n" 55 " gl_Position = projectionMatrix * vPosition;\n" 56 " v_texCoord = vPosition.xy * fillPortion.zw + fillPortion.xy;\n" 57 "}\n"; 58 59 static const char gRepeatTexFragmentShader[] = 60 "precision mediump float;\n" 61 "varying vec2 v_texCoord; \n" 62 "uniform float alpha; \n" 63 "uniform sampler2D s_texture; \n" 64 "uniform vec2 repeatScale;\n" 65 "void main() {\n" 66 " vec2 repeatedTexCoord; " 67 " repeatedTexCoord.x = v_texCoord.x - floor(v_texCoord.x); " 68 " repeatedTexCoord.y = v_texCoord.y - floor(v_texCoord.y); " 69 " repeatedTexCoord.x = repeatedTexCoord.x * repeatScale.x; " 70 " repeatedTexCoord.y = repeatedTexCoord.y * repeatScale.y; " 71 " gl_FragColor = texture2D(s_texture, repeatedTexCoord); \n" 72 " gl_FragColor *= alpha; " 73 "}\n"; 74 75 static const char gRepeatTexFragmentShaderInverted[] = 76 "precision mediump float;\n" 77 "varying vec2 v_texCoord; \n" 78 "uniform float alpha; \n" 79 "uniform float contrast; \n" 80 "uniform sampler2D s_texture; \n" 81 "uniform vec2 repeatScale;\n" 82 "void main() {\n" 83 " vec2 repeatedTexCoord; " 84 " repeatedTexCoord.x = v_texCoord.x - floor(v_texCoord.x); " 85 " repeatedTexCoord.y = v_texCoord.y - floor(v_texCoord.y); " 86 " repeatedTexCoord.x = repeatedTexCoord.x * repeatScale.x; " 87 " repeatedTexCoord.y = repeatedTexCoord.y * repeatScale.y; " 88 " vec4 pixel = texture2D(s_texture, repeatedTexCoord); \n" 89 " float a = pixel.a; \n" 90 " float color = a - (0.2989 * pixel.r + 0.5866 * pixel.g + 0.1145 * pixel.b);\n" 91 " color = ((color - a/2.0) * contrast) + a/2.0; \n" 92 " pixel.rgb = vec3(color, color, color); \n " 93 " gl_FragColor = pixel; \n" 94 " gl_FragColor *= alpha; " 95 "}\n"; 96 97 static const char gFragmentShader[] = 98 "precision mediump float;\n" 99 "varying vec2 v_texCoord; \n" 100 "uniform float alpha; \n" 101 "uniform sampler2D s_texture; \n" 102 "void main() {\n" 103 " gl_FragColor = texture2D(s_texture, v_texCoord); \n" 104 " gl_FragColor *= alpha; " 105 "}\n"; 106 107 // We could pass the pureColor into either Vertex or Frag Shader. 108 // The reason we passed the color into the Vertex Shader is that some driver 109 // might create redundant copy when uniforms in fragment shader changed. 110 static const char gPureColorVertexShader[] = 111 "attribute vec4 vPosition;\n" 112 "uniform mat4 projectionMatrix;\n" 113 "uniform vec4 inputColor;\n" 114 "varying vec4 v_color;\n" 115 "void main() {\n" 116 " gl_Position = projectionMatrix * vPosition;\n" 117 " v_color = inputColor;\n" 118 "}\n"; 119 120 static const char gPureColorFragmentShader[] = 121 "precision mediump float;\n" 122 "varying vec4 v_color;\n" 123 "void main() {\n" 124 " gl_FragColor = v_color;\n" 125 "}\n"; 126 127 static const char gFragmentShaderInverted[] = 128 "precision mediump float;\n" 129 "varying vec2 v_texCoord; \n" 130 "uniform float alpha; \n" 131 "uniform float contrast; \n" 132 "uniform sampler2D s_texture; \n" 133 "void main() {\n" 134 " vec4 pixel = texture2D(s_texture, v_texCoord); \n" 135 " float a = pixel.a; \n" 136 " float color = a - (0.2989 * pixel.r + 0.5866 * pixel.g + 0.1145 * pixel.b);\n" 137 " color = ((color - a/2.0) * contrast) + a/2.0; \n" 138 " pixel.rgb = vec3(color, color, color); \n " 139 " gl_FragColor = pixel; \n" 140 " gl_FragColor *= alpha; \n" 141 "}\n"; 142 143 static const char gVideoVertexShader[] = 144 "attribute vec4 vPosition;\n" 145 "uniform mat4 textureMatrix;\n" 146 "uniform mat4 projectionMatrix;\n" 147 "varying vec2 v_texCoord;\n" 148 "void main() {\n" 149 " gl_Position = projectionMatrix * vPosition;\n" 150 " v_texCoord = vec2(textureMatrix * vec4(vPosition.x, 1.0 - vPosition.y, 0.0, 1.0));\n" 151 "}\n"; 152 153 static const char gVideoFragmentShader[] = 154 "#extension GL_OES_EGL_image_external : require\n" 155 "precision mediump float;\n" 156 "uniform samplerExternalOES s_yuvTexture;\n" 157 "varying vec2 v_texCoord;\n" 158 "void main() {\n" 159 " gl_FragColor = texture2D(s_yuvTexture, v_texCoord);\n" 160 "}\n"; 161 162 static const char gSurfaceTextureOESFragmentShader[] = 163 "#extension GL_OES_EGL_image_external : require\n" 164 "precision mediump float;\n" 165 "varying vec2 v_texCoord; \n" 166 "uniform float alpha; \n" 167 "uniform samplerExternalOES s_texture; \n" 168 "void main() {\n" 169 " gl_FragColor = texture2D(s_texture, v_texCoord); \n" 170 " gl_FragColor *= alpha; " 171 "}\n"; 172 173 static const char gSurfaceTextureOESFragmentShaderInverted[] = 174 "#extension GL_OES_EGL_image_external : require\n" 175 "precision mediump float;\n" 176 "varying vec2 v_texCoord; \n" 177 "uniform float alpha; \n" 178 "uniform float contrast; \n" 179 "uniform samplerExternalOES s_texture; \n" 180 "void main() {\n" 181 " vec4 pixel = texture2D(s_texture, v_texCoord); \n" 182 " float a = pixel.a; \n" 183 " float color = a - (0.2989 * pixel.r + 0.5866 * pixel.g + 0.1145 * pixel.b);\n" 184 " color = ((color - a/2.0) * contrast) + a/2.0; \n" 185 " pixel.rgb = vec3(color, color, color); \n " 186 " gl_FragColor = pixel; \n" 187 " gl_FragColor *= alpha; \n" 188 "}\n"; 189 190 GLuint ShaderProgram::loadShader(GLenum shaderType, const char* pSource) 191 { 192 GLuint shader = glCreateShader(shaderType); 193 if (shader) { 194 glShaderSource(shader, 1, &pSource, 0); 195 glCompileShader(shader); 196 GLint compiled = 0; 197 glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); 198 if (!compiled) { 199 GLint infoLen = 0; 200 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); 201 if (infoLen) { 202 char* buf = (char*) malloc(infoLen); 203 if (buf) { 204 glGetShaderInfoLog(shader, infoLen, 0, buf); 205 ALOGE("could not compile shader %d:\n%s\n", shaderType, buf); 206 free(buf); 207 } 208 glDeleteShader(shader); 209 shader = 0; 210 } 211 } 212 } 213 return shader; 214 } 215 216 GLint ShaderProgram::createProgram(const char* pVertexSource, const char* pFragmentSource) 217 { 218 GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource); 219 if (!vertexShader) { 220 ALOGE("couldn't load the vertex shader!"); 221 return -1; 222 } 223 224 GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource); 225 if (!pixelShader) { 226 ALOGE("couldn't load the pixel shader!"); 227 return -1; 228 } 229 230 GLuint program = glCreateProgram(); 231 if (program) { 232 glAttachShader(program, vertexShader); 233 GLUtils::checkGlError("glAttachShader vertex"); 234 glAttachShader(program, pixelShader); 235 GLUtils::checkGlError("glAttachShader pixel"); 236 glLinkProgram(program); 237 GLint linkStatus = GL_FALSE; 238 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); 239 if (linkStatus != GL_TRUE) { 240 GLint bufLength = 0; 241 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); 242 if (bufLength) { 243 char* buf = (char*) malloc(bufLength); 244 if (buf) { 245 glGetProgramInfoLog(program, bufLength, 0, buf); 246 ALOGE("could not link program:\n%s\n", buf); 247 free(buf); 248 } 249 } 250 glDeleteProgram(program); 251 program = -1; 252 } 253 } 254 255 ShaderResource newResource(program, vertexShader, pixelShader); 256 m_resources.append(newResource); 257 return program; 258 } 259 260 void ShaderProgram::initProgram(ShaderType type) 261 { 262 // initialize shader's static texSampler and position values 263 glUseProgram(m_handleArray[type].programHandle); 264 265 if (m_handleArray[type].texSamplerHandle != -1) 266 glUniform1i(m_handleArray[type].texSamplerHandle, 0); 267 glEnableVertexAttribArray(m_handleArray[type].positionHandle); 268 } 269 270 ShaderProgram::ShaderProgram() 271 : m_blendingEnabled(false) 272 , m_contrast(1) 273 , m_alphaLayer(false) 274 , m_currentScale(1.0f) 275 , m_needsInit(true) 276 { 277 // initialize the matrix to calculate z values correctly, since it can be 278 // used for that before setupDrawing is called. 279 GLUtils::setOrthographicMatrix(m_visibleContentRectProjectionMatrix, 280 0,0,1,1, 281 -1000, 1000); 282 } 283 284 void ShaderProgram::cleanupGLResources() 285 { 286 for (unsigned int i = 0; i < m_resources.size(); i++) { 287 glDetachShader(m_resources[i].program, m_resources[i].vertexShader); 288 glDetachShader(m_resources[i].program, m_resources[i].fragmentShader); 289 glDeleteShader(m_resources[i].vertexShader); 290 glDeleteShader(m_resources[i].fragmentShader); 291 glDeleteProgram(m_resources[i].program); 292 } 293 glDeleteBuffers(1, m_textureBuffer); 294 295 m_resources.clear(); 296 m_needsInit = true; 297 GLUtils::checkGlError("cleanupGLResources"); 298 299 return; 300 } 301 302 void ShaderProgram::initGLResources() 303 { 304 // To detect whether or not resources for ShaderProgram allocated 305 // successfully, we clean up pre-existing errors here and will check for 306 // new errors at the end of this function. 307 GLUtils::checkGlError("before initGLResources"); 308 309 GLint tex2DProgram = createProgram(gVertexShader, gFragmentShader); 310 GLint pureColorProgram = createProgram(gPureColorVertexShader, gPureColorFragmentShader); 311 GLint tex2DInvProgram = createProgram(gVertexShader, gFragmentShaderInverted); 312 GLint videoProgram = createProgram(gVideoVertexShader, gVideoFragmentShader); 313 GLint texOESProgram = 314 createProgram(gVertexShader, gSurfaceTextureOESFragmentShader); 315 GLint texOESInvProgram = 316 createProgram(gVertexShader, gSurfaceTextureOESFragmentShaderInverted); 317 GLint repeatTexProgram = 318 createProgram(gVertexShader, gRepeatTexFragmentShader); 319 GLint repeatTexInvProgram = 320 createProgram(gVertexShader, gRepeatTexFragmentShaderInverted); 321 322 if (tex2DProgram == -1 323 || pureColorProgram == -1 324 || tex2DInvProgram == -1 325 || videoProgram == -1 326 || texOESProgram == -1 327 || texOESInvProgram == -1 328 || repeatTexProgram == -1 329 || repeatTexInvProgram == -1) { 330 m_needsInit = true; 331 return; 332 } 333 334 GLint pureColorPosition = glGetAttribLocation(pureColorProgram, "vPosition"); 335 GLint pureColorProjMtx = glGetUniformLocation(pureColorProgram, "projectionMatrix"); 336 GLint pureColorValue = glGetUniformLocation(pureColorProgram, "inputColor"); 337 m_handleArray[PureColor].init(-1, -1, pureColorPosition, pureColorProgram, 338 pureColorProjMtx, pureColorValue, -1, -1, -1, -1); 339 initProgram(PureColor); 340 341 GLint tex2DAlpha = glGetUniformLocation(tex2DProgram, "alpha"); 342 GLint tex2DPosition = glGetAttribLocation(tex2DProgram, "vPosition"); 343 GLint tex2DProjMtx = glGetUniformLocation(tex2DProgram, "projectionMatrix"); 344 GLint tex2DTexSampler = glGetUniformLocation(tex2DProgram, "s_texture"); 345 GLint tex2DFillPortion = glGetUniformLocation(tex2DProgram, "fillPortion"); 346 m_handleArray[Tex2D].init(tex2DAlpha, -1, tex2DPosition, tex2DProgram, 347 tex2DProjMtx, -1, tex2DTexSampler, -1, tex2DFillPortion, -1); 348 initProgram(Tex2D); 349 350 GLint tex2DInvAlpha = glGetUniformLocation(tex2DInvProgram, "alpha"); 351 GLint tex2DInvContrast = glGetUniformLocation(tex2DInvProgram, "contrast"); 352 GLint tex2DInvPosition = glGetAttribLocation(tex2DInvProgram, "vPosition"); 353 GLint tex2DInvProjMtx = glGetUniformLocation(tex2DInvProgram, "projectionMatrix"); 354 GLint tex2DInvTexSampler = glGetUniformLocation(tex2DInvProgram, "s_texture"); 355 GLint tex2DInvFillPortion = glGetUniformLocation(tex2DInvProgram, "fillPortion"); 356 m_handleArray[Tex2DInv].init(tex2DInvAlpha, tex2DInvContrast, 357 tex2DInvPosition, tex2DInvProgram, 358 tex2DInvProjMtx, -1, 359 tex2DInvTexSampler, -1, tex2DInvFillPortion, -1); 360 initProgram(Tex2DInv); 361 362 GLint repeatTexAlpha = glGetUniformLocation(repeatTexProgram, "alpha"); 363 GLint repeatTexPosition = glGetAttribLocation(repeatTexProgram, "vPosition"); 364 GLint repeatTexProjMtx = glGetUniformLocation(repeatTexProgram, "projectionMatrix"); 365 GLint repeatTexTexSampler = glGetUniformLocation(repeatTexProgram, "s_texture"); 366 GLint repeatTexFillPortion = glGetUniformLocation(repeatTexProgram, "fillPortion"); 367 GLint repeatTexScale = glGetUniformLocation(repeatTexProgram, "repeatScale"); 368 m_handleArray[RepeatTex].init(repeatTexAlpha, -1, repeatTexPosition, 369 repeatTexProgram,repeatTexProjMtx, -1, 370 repeatTexTexSampler, -1, repeatTexFillPortion, 371 repeatTexScale); 372 initProgram(RepeatTex); 373 374 GLint repeatTexInvAlpha = glGetUniformLocation(repeatTexInvProgram, "alpha"); 375 GLint repeatTexInvContrast = glGetUniformLocation(tex2DInvProgram, "contrast"); 376 GLint repeatTexInvPosition = glGetAttribLocation(repeatTexInvProgram, "vPosition"); 377 GLint repeatTexInvProjMtx = glGetUniformLocation(repeatTexInvProgram, "projectionMatrix"); 378 GLint repeatTexInvTexSampler = glGetUniformLocation(repeatTexInvProgram, "s_texture"); 379 GLint repeatTexInvFillPortion = glGetUniformLocation(repeatTexInvProgram, "fillPortion"); 380 GLint repeatTexInvScale = glGetUniformLocation(repeatTexInvProgram, "repeatScale"); 381 m_handleArray[RepeatTexInv].init(repeatTexInvAlpha, repeatTexInvContrast, 382 repeatTexInvPosition, repeatTexInvProgram, 383 repeatTexInvProjMtx, -1, 384 repeatTexInvTexSampler, -1, 385 repeatTexInvFillPortion, repeatTexInvScale); 386 initProgram(RepeatTexInv); 387 388 GLint texOESAlpha = glGetUniformLocation(texOESProgram, "alpha"); 389 GLint texOESPosition = glGetAttribLocation(texOESProgram, "vPosition"); 390 GLint texOESProjMtx = glGetUniformLocation(texOESProgram, "projectionMatrix"); 391 GLint texOESTexSampler = glGetUniformLocation(texOESProgram, "s_texture"); 392 GLint texOESFillPortion = glGetUniformLocation(texOESProgram, "fillPortion"); 393 m_handleArray[TexOES].init(texOESAlpha, -1, texOESPosition, texOESProgram, 394 texOESProjMtx, -1, texOESTexSampler, -1, texOESFillPortion, -1); 395 initProgram(TexOES); 396 397 GLint texOESInvAlpha = glGetUniformLocation(texOESInvProgram, "alpha"); 398 GLint texOESInvContrast = glGetUniformLocation(texOESInvProgram, "contrast"); 399 GLint texOESInvPosition = glGetAttribLocation(texOESInvProgram, "vPosition"); 400 GLint texOESInvProjMtx = glGetUniformLocation(texOESInvProgram, "projectionMatrix"); 401 GLint texOESInvTexSampler = glGetUniformLocation(texOESInvProgram, "s_texture"); 402 GLint texOESInvFillPortion = glGetUniformLocation(texOESInvProgram, "fillPortion"); 403 m_handleArray[TexOESInv].init(texOESInvAlpha, texOESInvContrast, 404 texOESInvPosition, texOESInvProgram, 405 texOESInvProjMtx, -1, 406 texOESInvTexSampler, -1, texOESInvFillPortion, -1); 407 initProgram(TexOESInv); 408 409 GLint videoPosition = glGetAttribLocation(videoProgram, "vPosition"); 410 GLint videoProjMtx = glGetUniformLocation(videoProgram, "projectionMatrix"); 411 GLint videoTexSampler = glGetUniformLocation(videoProgram, "s_yuvTexture"); 412 GLint videoTexMtx = glGetUniformLocation(videoProgram, "textureMatrix"); 413 m_handleArray[Video].init(-1, -1, videoPosition, videoProgram, 414 videoProjMtx, -1, videoTexSampler, 415 videoTexMtx, -1, -1); 416 initProgram(Video); 417 418 const GLfloat coord[] = { 419 0.0f, 0.0f, // C 420 1.0f, 0.0f, // D 421 0.0f, 1.0f, // A 422 1.0f, 1.0f // B 423 }; 424 425 glGenBuffers(1, m_textureBuffer); 426 glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]); 427 glBufferData(GL_ARRAY_BUFFER, 2 * 4 * sizeof(GLfloat), coord, GL_STATIC_DRAW); 428 429 TransformationMatrix matrix; 430 // Map x,y from (0,1) to (-1, 1) 431 matrix.scale3d(2, 2, 1); 432 matrix.translate3d(-0.5, -0.5, 0); 433 GLUtils::toGLMatrix(m_transferProjMtx, matrix); 434 435 m_needsInit = GLUtils::checkGlError("initGLResources"); 436 return; 437 } 438 439 void ShaderProgram::resetBlending() 440 { 441 glDisable(GL_BLEND); 442 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 443 glBlendEquation(GL_FUNC_ADD); 444 m_blendingEnabled = false; 445 } 446 447 void ShaderProgram::setBlendingState(bool enableBlending) 448 { 449 if (enableBlending == m_blendingEnabled) 450 return; 451 452 if (enableBlending) 453 glEnable(GL_BLEND); 454 else 455 glDisable(GL_BLEND); 456 457 m_blendingEnabled = enableBlending; 458 } 459 460 ///////////////////////////////////////////////////////////////////////////////////////// 461 // Drawing 462 ///////////////////////////////////////////////////////////////////////////////////////// 463 464 // We have multiple coordinates to deal with: first is the screen coordinates, 465 // second is the view coordinates and the last one is content(document) coordinates. 466 // Both screen and view coordinates are in pixels. 467 // All these coordinates start from upper left, but for the purpose of OpenGL 468 // operations, we may need a inverted Y version of such coordinates which 469 // start from lower left. 470 // 471 // invScreenRect - inv screen coordinates starting from lower left. 472 // visibleContentRect - local content(document) coordinates starting from upper left. 473 // screenRect - screen coordinates starting from upper left. 474 // screenClip - screen coordinates starting from upper left. 475 // ------------------------------------------ 476 // |(origin of screen) | 477 // |screen | 478 // | --------------------------------- | 479 // | | (origin of view) | | 480 // | | webview | | 481 // | | -------- | | 482 // | | | clip | | | 483 // | | | | | | 484 // | | -------- | | 485 // | | | | 486 // | |(origin of inv view) | | 487 // | --------------------------------- | 488 // |(origin of inv screen) | 489 // ------------------------------------------ 490 void ShaderProgram::setupDrawing(const IntRect& invScreenRect, 491 const SkRect& visibleContentRect, 492 const IntRect& screenRect, int titleBarHeight, 493 const IntRect& screenClip, float scale) 494 { 495 m_screenRect = screenRect; 496 m_titleBarHeight = titleBarHeight; 497 498 //// viewport //// 499 GLUtils::setOrthographicMatrix(m_visibleContentRectProjectionMatrix, 500 visibleContentRect.fLeft, 501 visibleContentRect.fTop, 502 visibleContentRect.fRight, 503 visibleContentRect.fBottom, 504 -1000, 1000); 505 506 ALOGV("set m_clipProjectionMatrix, %d, %d, %d, %d", 507 screenClip.x(), screenClip.y(), screenClip.x() + screenClip.width(), 508 screenClip.y() + screenClip.height()); 509 510 // In order to incorporate the animation delta X and Y, using the clip as 511 // the GL viewport can save all the trouble of re-position from screenRect 512 // to final position. 513 GLUtils::setOrthographicMatrix(m_clipProjectionMatrix, screenClip.x(), screenClip.y(), 514 screenClip.x() + screenClip.width(), 515 screenClip.y() + screenClip.height(), -1000, 1000); 516 517 glViewport(screenClip.x(), m_targetHeight - screenClip.y() - screenClip.height() , 518 screenClip.width(), screenClip.height()); 519 520 m_visibleContentRect = visibleContentRect; 521 m_currentScale = scale; 522 523 524 //// viewRect //// 525 m_invScreenRect = invScreenRect; 526 527 // The following matrices transform content coordinates into view coordinates 528 // and inv view coordinates. 529 // Note that GLUtils::setOrthographicMatrix is inverting the Y. 530 TransformationMatrix viewTranslate; 531 viewTranslate.translate(1.0, 1.0); 532 533 TransformationMatrix viewScale; 534 viewScale.scale3d(m_invScreenRect.width() * 0.5f, m_invScreenRect.height() * 0.5f, 1); 535 536 m_contentToInvViewMatrix = viewScale * viewTranslate * m_visibleContentRectProjectionMatrix; 537 538 viewTranslate.scale3d(1, -1, 1); 539 m_contentToViewMatrix = viewScale * viewTranslate * m_visibleContentRectProjectionMatrix; 540 541 IntRect invViewRect(0, 0, m_screenRect.width(), m_screenRect.height()); 542 m_contentViewport = m_contentToInvViewMatrix.inverse().mapRect(invViewRect); 543 544 545 //// clipping //// 546 IntRect viewClip = screenClip; 547 548 // The incoming screenClip is in screen coordinates, we first 549 // translate it into view coordinates. 550 // Then we convert it into inverted view coordinates. 551 // Therefore, in the clip() function, we need to convert things back from 552 // inverted view coordinates to inverted screen coordinates which is used by GL. 553 viewClip.setX(screenClip.x() - m_screenRect.x()); 554 viewClip.setY(screenClip.y() - m_screenRect.y() - m_titleBarHeight); 555 FloatRect invViewClip = convertViewCoordToInvViewCoord(viewClip); 556 m_invViewClip.setLocation(IntPoint(invViewClip.x(), invViewClip.y())); 557 // use ceilf to handle view -> doc -> view coord rounding errors 558 m_invViewClip.setSize(IntSize(ceilf(invViewClip.width()), ceilf(invViewClip.height()))); 559 560 resetBlending(); 561 562 // Set up m_clipProjectionMatrix, m_currentScale and m_webViewMatrix before 563 // calling this function. 564 setupSurfaceProjectionMatrix(); 565 566 //// initialize frame-constant values //// 567 glActiveTexture(GL_TEXTURE0); 568 glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]); 569 570 //// initialize GL cache //// 571 m_cachedProgramType = UndefinedShader; 572 m_cachedOpacity = -1; 573 m_cachedFillPortion = FloatRect(); 574 m_cachedPureColor = Color(); 575 } 576 577 // Calculate the right color value sent into the shader considering the (0,1) 578 // clamp and alpha blending. 579 Color ShaderProgram::shaderColor(Color pureColor, float opacity) 580 { 581 float r = pureColor.red() / 255.0; 582 float g = pureColor.green() / 255.0; 583 float b = pureColor.blue() / 255.0; 584 float a = pureColor.alpha() / 255.0; 585 586 if (TilesManager::instance()->invertedScreen()) { 587 float intensity = a - (0.2989 * r + 0.5866 * g + 0.1145 * b); 588 intensity = ((intensity - a / 2.0) * m_contrast) + a / 2.0; 589 intensity *= opacity; 590 return Color(intensity, intensity, intensity, a * opacity); 591 } 592 return Color(r * opacity, g * opacity, b * opacity, a * opacity); 593 } 594 595 // For shaders using texture, it is easy to get the type from the textureTarget. 596 ShaderType ShaderProgram::getTextureShaderType(GLenum textureTarget, 597 bool hasRepeatScale) 598 { 599 ShaderType type = UndefinedShader; 600 if (textureTarget == GL_TEXTURE_2D) { 601 if (!TilesManager::instance()->invertedScreen()) 602 type = hasRepeatScale ? RepeatTex : Tex2D; 603 else { 604 // With the new GPU texture upload path, we do not use an FBO 605 // to blit the texture we receive from the TexturesGenerator thread. 606 // To implement inverted rendering, we thus have to do the rendering 607 // live, by using a different shader. 608 type = hasRepeatScale ? RepeatTexInv : Tex2DInv; 609 } 610 } else if (textureTarget == GL_TEXTURE_EXTERNAL_OES) { 611 if (!TilesManager::instance()->invertedScreen()) 612 type = TexOES; 613 else 614 type = TexOESInv; 615 } 616 return type; 617 } 618 619 // This function transform a clip rect extracted from the current layer 620 // into a clip rect in InvView coordinates -- used by the clipping rects 621 FloatRect ShaderProgram::rectInInvViewCoord(const TransformationMatrix& drawMatrix, const IntSize& size) 622 { 623 FloatRect srect(0, 0, size.width(), size.height()); 624 TransformationMatrix renderMatrix = m_contentToInvViewMatrix * drawMatrix; 625 return renderMatrix.mapRect(srect); 626 } 627 628 // used by the partial screen invals 629 FloatRect ShaderProgram::rectInViewCoord(const TransformationMatrix& drawMatrix, const IntSize& size) 630 { 631 FloatRect srect(0, 0, size.width(), size.height()); 632 TransformationMatrix renderMatrix = m_contentToViewMatrix * drawMatrix; 633 return renderMatrix.mapRect(srect); 634 } 635 636 FloatRect ShaderProgram::rectInViewCoord(const FloatRect& rect) 637 { 638 return m_contentToViewMatrix.mapRect(rect); 639 } 640 641 FloatRect ShaderProgram::rectInInvViewCoord(const FloatRect& rect) 642 { 643 return m_contentToInvViewMatrix.mapRect(rect); 644 } 645 646 FloatRect ShaderProgram::convertInvViewCoordToContentCoord(const FloatRect& rect) 647 { 648 return m_contentToInvViewMatrix.inverse().mapRect(rect); 649 } 650 651 FloatRect ShaderProgram::convertViewCoordToInvViewCoord(const FloatRect& rect) 652 { 653 FloatRect visibleContentRect = m_contentToViewMatrix.inverse().mapRect(rect); 654 return rectInInvViewCoord(visibleContentRect); 655 } 656 657 FloatRect ShaderProgram::convertInvViewCoordToViewCoord(const FloatRect& rect) 658 { 659 FloatRect visibleContentRect = m_contentToInvViewMatrix.inverse().mapRect(rect); 660 return rectInViewCoord(visibleContentRect); 661 } 662 663 // clip is in screen coordinates 664 void ShaderProgram::clip(const FloatRect& clip) 665 { 666 if (clip == m_clipRect) 667 return; 668 669 ALOGV("--clipping rect %f %f, %f x %f", 670 clip.x(), clip.y(), clip.width(), clip.height()); 671 672 // we should only call glScissor in this function, so that we can easily 673 // track the current clipping rect. 674 675 IntRect screenClip(clip.x(), 676 clip.y(), 677 clip.width(), clip.height()); 678 679 if (!m_invViewClip.isEmpty()) 680 screenClip.intersect(m_invViewClip); 681 682 // The previous intersection calculation is using local screen coordinates. 683 // Now we need to convert things from local screen coordinates to global 684 // screen coordinates and pass to the GL functions. 685 screenClip.setX(screenClip.x() + m_invScreenRect.x()); 686 screenClip.setY(screenClip.y() + m_invScreenRect.y()); 687 if (screenClip.x() < 0) { 688 int w = screenClip.width(); 689 w += screenClip.x(); 690 screenClip.setX(0); 691 screenClip.setWidth(w); 692 } 693 if (screenClip.y() < 0) { 694 int h = screenClip.height(); 695 h += screenClip.y(); 696 screenClip.setY(0); 697 screenClip.setHeight(h); 698 } 699 700 glScissor(screenClip.x(), screenClip.y(), screenClip.width(), screenClip.height()); 701 702 m_clipRect = clip; 703 } 704 705 IntRect ShaderProgram::clippedRectWithVisibleContentRect(const IntRect& rect, int margin) 706 { 707 IntRect viewport(m_visibleContentRect.fLeft - margin, m_visibleContentRect.fTop - margin, 708 m_visibleContentRect.width() + margin, 709 m_visibleContentRect.height() + margin); 710 viewport.intersect(rect); 711 return viewport; 712 } 713 714 float ShaderProgram::zValue(const TransformationMatrix& drawMatrix, float w, float h) 715 { 716 TransformationMatrix modifiedDrawMatrix = drawMatrix; 717 modifiedDrawMatrix.scale3d(w, h, 1); 718 TransformationMatrix renderMatrix = 719 m_visibleContentRectProjectionMatrix * modifiedDrawMatrix; 720 FloatPoint3D point(0.5, 0.5, 0.0); 721 FloatPoint3D result = renderMatrix.mapPoint(point); 722 return result.z(); 723 } 724 725 void ShaderProgram::drawQuadInternal(ShaderType type, const GLfloat* matrix, 726 int textureId, float opacity, 727 GLenum textureTarget, GLenum filter, 728 const Color& pureColor, const FloatRect& fillPortion, 729 const FloatSize& repeatScale) 730 { 731 if (m_cachedProgramType != type) { 732 glUseProgram(m_handleArray[type].programHandle); 733 glVertexAttribPointer(m_handleArray[type].positionHandle, 734 2, GL_FLOAT, GL_FALSE, 0, 0); 735 m_cachedProgramType = type; 736 m_cachedFillPortion = FloatRect(); 737 m_cachedOpacity = -1; // reset cache for variable shared by multiple programs 738 } 739 glUniformMatrix4fv(m_handleArray[type].projMtxHandle, 1, GL_FALSE, matrix); 740 741 if (type != PureColor) { 742 glBindTexture(textureTarget, textureId); 743 glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, filter); 744 glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, filter); 745 746 if (m_cachedOpacity != opacity) { 747 glUniform1f(m_handleArray[type].alphaHandle, opacity); 748 m_cachedOpacity = opacity; 749 } 750 751 GLint contrastHandle = m_handleArray[type].contrastHandle; 752 if (contrastHandle != -1) 753 glUniform1f(contrastHandle, m_contrast); 754 755 if (m_cachedFillPortion != fillPortion) { 756 glUniform4f(m_handleArray[type].fillPortionHandle, fillPortion.x(), fillPortion.y(), 757 fillPortion.width(), fillPortion.height()); 758 m_cachedFillPortion = fillPortion; 759 } 760 761 // Only when we have repeat scale, this handle can be >= 0; 762 if (m_handleArray[type].scaleHandle != -1) { 763 glUniform2f(m_handleArray[type].scaleHandle, 764 repeatScale.width(), repeatScale.height()); 765 } 766 } else { 767 if (m_cachedPureColor != pureColor) { 768 glUniform4f(m_handleArray[type].pureColorHandle, 769 pureColor.red() / 255.0, pureColor.green() / 255.0, 770 pureColor.blue() / 255.0, pureColor.alpha() / 255.0); 771 m_cachedPureColor = pureColor; 772 } 773 } 774 775 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 776 } 777 778 // Put the common matrix computation at higher level to avoid redundancy. 779 void ShaderProgram::setupSurfaceProjectionMatrix() 780 { 781 TransformationMatrix scaleMatrix; 782 scaleMatrix.scale3d(m_currentScale, m_currentScale, 1); 783 m_surfaceProjectionMatrix = m_clipProjectionMatrix * m_webViewMatrix * scaleMatrix; 784 } 785 786 // Calculate the matrix given the geometry. 787 GLfloat* ShaderProgram::getTileProjectionMatrix(const DrawQuadData* data) 788 { 789 DrawQuadType type = data->type(); 790 if (type == Blit) 791 return m_transferProjMtx; 792 793 const TransformationMatrix* matrix = data->drawMatrix(); 794 const SkRect* geometry = data->geometry(); 795 FloatRect fillPortion = data->fillPortion(); 796 ALOGV("fillPortion " FLOAT_RECT_FORMAT, FLOAT_RECT_ARGS(fillPortion)); 797 798 // This modifiedDrawMatrix tranform (0,0)(1x1) to the final rect in screen 799 // coordinates, before applying the m_webViewMatrix. 800 // It first scale and translate the vertex array from (0,0)(1x1) to real 801 // tile position and size. Then apply the transform from the layer's. 802 // Finally scale to the currentScale to support zooming. 803 // Note the geometry contains the tile zoom scale, so visually we will see 804 // the tiles scale at a ratio as (m_currentScale/tile's scale). 805 TransformationMatrix modifiedDrawMatrix; 806 if (type == LayerQuad) 807 modifiedDrawMatrix = *matrix; 808 modifiedDrawMatrix.translate(geometry->fLeft + geometry->width() * fillPortion.x(), 809 geometry->fTop + geometry->height() * fillPortion.y()); 810 modifiedDrawMatrix.scale3d(geometry->width() * fillPortion.width(), 811 geometry->height() * fillPortion.height(), 1); 812 813 // Even when we are on a alpha layer or not, we need to respect the 814 // m_webViewMatrix, it may contain the layout offset. Normally it is 815 // identity. 816 TransformationMatrix renderMatrix; 817 renderMatrix = m_surfaceProjectionMatrix * modifiedDrawMatrix; 818 819 #if DEBUG_MATRIX 820 debugMatrixInfo(m_currentScale, m_clipProjectionMatrix, m_webViewMatrix, 821 modifiedDrawMatrix, matrix); 822 #endif 823 824 GLUtils::toGLMatrix(m_tileProjMatrix, renderMatrix); 825 return m_tileProjMatrix; 826 } 827 828 void ShaderProgram::drawQuad(const DrawQuadData* data) 829 { 830 GLfloat* matrix = getTileProjectionMatrix(data); 831 832 float opacity = data->opacity(); 833 bool forceBlending = data->forceBlending(); 834 bool enableBlending = forceBlending || opacity < 1.0; 835 836 ShaderType shaderType = UndefinedShader; 837 int textureId = 0; 838 GLint textureFilter = 0; 839 GLenum textureTarget = 0; 840 841 Color quadColor = data->quadColor(); 842 if (data->pureColor()) { 843 shaderType = PureColor; 844 quadColor = shaderColor(quadColor, opacity); 845 enableBlending = enableBlending || quadColor.hasAlpha(); 846 if (!quadColor.alpha() && enableBlending) 847 return; 848 } else { 849 textureId = data->textureId(); 850 textureFilter = data->textureFilter(); 851 textureTarget = data->textureTarget(); 852 shaderType = getTextureShaderType(textureTarget, data->hasRepeatScale()); 853 } 854 setBlendingState(enableBlending); 855 drawQuadInternal(shaderType, matrix, textureId, opacity, 856 textureTarget, textureFilter, quadColor, data->fillPortion(), 857 data->repeatScale()); 858 } 859 860 void ShaderProgram::drawVideoLayerQuad(const TransformationMatrix& drawMatrix, 861 float* textureMatrix, SkRect& geometry, 862 int textureId) 863 { 864 // switch to our custom yuv video rendering program 865 if (m_cachedProgramType != Video) { 866 glUseProgram(m_handleArray[Video].programHandle); 867 glVertexAttribPointer(m_handleArray[Video].positionHandle, 868 2, GL_FLOAT, GL_FALSE, 0, 0); 869 m_cachedProgramType = Video; 870 } 871 872 // TODO: Merge drawVideoLayerQuad into drawQuad. 873 TransformationMatrix modifiedDrawMatrix; 874 modifiedDrawMatrix.scale3d(m_currentScale, m_currentScale, 1); 875 modifiedDrawMatrix.multiply(drawMatrix); 876 modifiedDrawMatrix.translate(geometry.fLeft, geometry.fTop); 877 modifiedDrawMatrix.scale3d(geometry.width(), geometry.height(), 1); 878 TransformationMatrix renderMatrix = 879 m_clipProjectionMatrix * m_webViewMatrix * modifiedDrawMatrix; 880 881 GLfloat projectionMatrix[16]; 882 GLUtils::toGLMatrix(projectionMatrix, renderMatrix); 883 glUniformMatrix4fv(m_handleArray[Video].projMtxHandle, 1, GL_FALSE, 884 projectionMatrix); 885 glUniformMatrix4fv(m_handleArray[Video].videoMtxHandle, 1, GL_FALSE, 886 textureMatrix); 887 glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureId); 888 889 setBlendingState(false); 890 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 891 } 892 893 void ShaderProgram::setGLDrawInfo(const android::uirenderer::DrawGlInfo* info) 894 { 895 GLUtils::convertToTransformationMatrix(info->transform, m_webViewMatrix); 896 m_alphaLayer = info->isLayer; 897 m_targetHeight = info->height; 898 } 899 900 // This function is called per tileGrid to minimize the computation overhead. 901 // The ortho projection and glViewport will map 1:1, so we don't need to 902 // worry about them here. Basically, if the current zoom scale / tile's scale 903 // plus the webview and layer transformation ends up at scale factor 1.0, 904 // then we can use point sampling. 905 bool ShaderProgram::usePointSampling(float tileScale, 906 const TransformationMatrix* layerTransform) 907 { 908 const float testSize = 1.0; 909 FloatRect rect(0, 0, testSize, testSize); 910 TransformationMatrix matrix; 911 matrix.scale3d(m_currentScale, m_currentScale, 1); 912 if (layerTransform) 913 matrix.multiply(*layerTransform); 914 matrix.scale3d(1.0 / tileScale, 1.0 / tileScale, 1); 915 916 matrix = m_webViewMatrix * matrix; 917 918 rect = matrix.mapRect(rect); 919 920 float deltaWidth = abs(rect.width() - testSize); 921 float deltaHeight = abs(rect.height() - testSize); 922 923 if (deltaWidth < EPSILON && deltaHeight < EPSILON) { 924 ALOGV("Point sampling : deltaWidth is %f, deltaHeight is %f", deltaWidth, deltaHeight); 925 return true; 926 } 927 return false; 928 } 929 930 #if DEBUG_MATRIX 931 FloatRect ShaderProgram::debugMatrixTransform(const TransformationMatrix& matrix, 932 const char* matrixName) 933 { 934 FloatRect rect(0.0, 0.0, 1.0, 1.0); 935 rect = matrix.mapRect(rect); 936 ALOGV("After %s matrix:\n %f, %f rect.width() %f rect.height() %f", 937 matrixName, rect.x(), rect.y(), rect.width(), rect.height()); 938 return rect; 939 940 } 941 942 void ShaderProgram::debugMatrixInfo(float currentScale, 943 const TransformationMatrix& clipProjectionMatrix, 944 const TransformationMatrix& webViewMatrix, 945 const TransformationMatrix& modifiedDrawMatrix, 946 const TransformationMatrix* layerMatrix) 947 { 948 int viewport[4]; 949 glGetIntegerv(GL_VIEWPORT, viewport); 950 ALOGV("viewport %d, %d, %d, %d , currentScale %f", 951 viewport[0], viewport[1], viewport[2], viewport[3], currentScale); 952 IntRect currentGLViewport(viewport[0], viewport[1], viewport[2], viewport[3]); 953 954 TransformationMatrix scaleMatrix; 955 scaleMatrix.scale3d(currentScale, currentScale, 1.0); 956 957 if (layerMatrix) 958 debugMatrixTransform(*layerMatrix, "layerMatrix"); 959 960 TransformationMatrix debugMatrix = scaleMatrix * modifiedDrawMatrix; 961 debugMatrixTransform(debugMatrix, "scaleMatrix * modifiedDrawMatrix"); 962 963 debugMatrix = webViewMatrix * debugMatrix; 964 debugMatrixTransform(debugMatrix, "webViewMatrix * scaleMatrix * modifiedDrawMatrix"); 965 966 debugMatrix = clipProjectionMatrix * debugMatrix; 967 FloatRect finalRect = 968 debugMatrixTransform(debugMatrix, "all Matrix"); 969 // After projection, we will be in a (-1, 1) range and now we can map it back 970 // to the (x,y) -> (x+width, y+height) 971 ALOGV("final convert to screen coord x, y %f, %f width %f height %f , ", 972 (finalRect.x() + 1) / 2 * currentGLViewport.width() + currentGLViewport.x(), 973 (finalRect.y() + 1) / 2 * currentGLViewport.height() + currentGLViewport.y(), 974 finalRect.width() * currentGLViewport.width() / 2, 975 finalRect.height() * currentGLViewport.height() / 2); 976 } 977 #endif // DEBUG_MATRIX 978 979 } // namespace WebCore 980 #endif // USE(ACCELERATED_COMPOSITING) 981