Home | History | Annotate | Download | only in rendering
      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