diff options
author | Nicolas Roard <nicolasroard@google.com> | 2012-04-06 11:35:50 -0700 |
---|---|---|
committer | Nicolas Roard <nicolasroard@google.com> | 2012-04-06 14:03:59 -0700 |
commit | 2e510fd5b5a30f1315c272d44ae3aa4cba355498 (patch) | |
tree | db3af5f32855d329856f190c3509ae11ae519851 /Source/WebCore/platform/graphics/android/rendering/ShaderProgram.cpp | |
parent | c88c88907b618e468ec3928b06a3a31d4f99b9c6 (diff) | |
download | external_webkit-2e510fd5b5a30f1315c272d44ae3aa4cba355498.zip external_webkit-2e510fd5b5a30f1315c272d44ae3aa4cba355498.tar.gz external_webkit-2e510fd5b5a30f1315c272d44ae3aa4cba355498.tar.bz2 |
Reorganize platform/graphics/android
Change-Id: Idc67155cfa99784dcd931e705336bfa063ecae46
Diffstat (limited to 'Source/WebCore/platform/graphics/android/rendering/ShaderProgram.cpp')
-rw-r--r-- | Source/WebCore/platform/graphics/android/rendering/ShaderProgram.cpp | 730 |
1 files changed, 730 insertions, 0 deletions
diff --git a/Source/WebCore/platform/graphics/android/rendering/ShaderProgram.cpp b/Source/WebCore/platform/graphics/android/rendering/ShaderProgram.cpp new file mode 100644 index 0000000..a0d9e56 --- /dev/null +++ b/Source/WebCore/platform/graphics/android/rendering/ShaderProgram.cpp @@ -0,0 +1,730 @@ +/* + * Copyright 2010, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define LOG_TAG "ShaderProgram" +#define LOG_NDEBUG 1 + +#include "config.h" +#include "ShaderProgram.h" + +#if USE(ACCELERATED_COMPOSITING) + +#include "AndroidLog.h" +#include "DrawQuadData.h" +#include "FloatPoint3D.h" +#include "GLUtils.h" +#include "TilesManager.h" + +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +namespace WebCore { + +static const char gVertexShader[] = + "attribute vec4 vPosition;\n" + "uniform mat4 projectionMatrix;\n" + "varying vec2 v_texCoord;\n" + "void main() {\n" + " gl_Position = projectionMatrix * vPosition;\n" + " v_texCoord = vec2(vPosition);\n" + "}\n"; + +static const char gFragmentShader[] = + "precision mediump float;\n" + "varying vec2 v_texCoord; \n" + "uniform float alpha; \n" + "uniform sampler2D s_texture; \n" + "void main() {\n" + " gl_FragColor = texture2D(s_texture, v_texCoord); \n" + " gl_FragColor *= alpha; " + "}\n"; + +// We could pass the pureColor into either Vertex or Frag Shader. +// The reason we passed the color into the Vertex Shader is that some driver +// might create redundant copy when uniforms in fragment shader changed. +static const char gPureColorVertexShader[] = + "attribute vec4 vPosition;\n" + "uniform mat4 projectionMatrix;\n" + "uniform vec4 inputColor;\n" + "varying vec4 v_color;\n" + "void main() {\n" + " gl_Position = projectionMatrix * vPosition;\n" + " v_color = inputColor;\n" + "}\n"; + +static const char gPureColorFragmentShader[] = + "precision mediump float;\n" + "varying vec4 v_color;\n" + "void main() {\n" + " gl_FragColor = v_color;\n" + "}\n"; + +static const char gFragmentShaderInverted[] = + "precision mediump float;\n" + "varying vec2 v_texCoord; \n" + "uniform float alpha; \n" + "uniform float contrast; \n" + "uniform sampler2D s_texture; \n" + "void main() {\n" + " vec4 pixel = texture2D(s_texture, v_texCoord); \n" + " float a = pixel.a; \n" + " float color = a - (0.2989 * pixel.r + 0.5866 * pixel.g + 0.1145 * pixel.b);\n" + " color = ((color - a/2.0) * contrast) + a/2.0; \n" + " pixel.rgb = vec3(color, color, color); \n " + " gl_FragColor = pixel; \n" + " gl_FragColor *= alpha; \n" + "}\n"; + +static const char gVideoVertexShader[] = + "attribute vec4 vPosition;\n" + "uniform mat4 textureMatrix;\n" + "uniform mat4 projectionMatrix;\n" + "varying vec2 v_texCoord;\n" + "void main() {\n" + " gl_Position = projectionMatrix * vPosition;\n" + " v_texCoord = vec2(textureMatrix * vec4(vPosition.x, 1.0 - vPosition.y, 0.0, 1.0));\n" + "}\n"; + +static const char gVideoFragmentShader[] = + "#extension GL_OES_EGL_image_external : require\n" + "precision mediump float;\n" + "uniform samplerExternalOES s_yuvTexture;\n" + "varying vec2 v_texCoord;\n" + "void main() {\n" + " gl_FragColor = texture2D(s_yuvTexture, v_texCoord);\n" + "}\n"; + +static const char gSurfaceTextureOESFragmentShader[] = + "#extension GL_OES_EGL_image_external : require\n" + "precision mediump float;\n" + "varying vec2 v_texCoord; \n" + "uniform float alpha; \n" + "uniform samplerExternalOES s_texture; \n" + "void main() {\n" + " gl_FragColor = texture2D(s_texture, v_texCoord); \n" + " gl_FragColor *= alpha; " + "}\n"; + +static const char gSurfaceTextureOESFragmentShaderInverted[] = + "#extension GL_OES_EGL_image_external : require\n" + "precision mediump float;\n" + "varying vec2 v_texCoord; \n" + "uniform float alpha; \n" + "uniform float contrast; \n" + "uniform samplerExternalOES s_texture; \n" + "void main() {\n" + " vec4 pixel = texture2D(s_texture, v_texCoord); \n" + " float a = pixel.a; \n" + " float color = a - (0.2989 * pixel.r + 0.5866 * pixel.g + 0.1145 * pixel.b);\n" + " color = ((color - a/2.0) * contrast) + a/2.0; \n" + " pixel.rgb = vec3(color, color, color); \n " + " gl_FragColor = pixel; \n" + " gl_FragColor *= alpha; \n" + "}\n"; + +GLuint ShaderProgram::loadShader(GLenum shaderType, const char* pSource) +{ + GLuint shader = glCreateShader(shaderType); + if (shader) { + glShaderSource(shader, 1, &pSource, 0); + glCompileShader(shader); + GLint compiled = 0; + glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); + if (!compiled) { + GLint infoLen = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); + if (infoLen) { + char* buf = (char*) malloc(infoLen); + if (buf) { + glGetShaderInfoLog(shader, infoLen, 0, buf); + ALOGE("could not compile shader %d:\n%s\n", shaderType, buf); + free(buf); + } + glDeleteShader(shader); + shader = 0; + } + } + } + return shader; +} + +GLint ShaderProgram::createProgram(const char* pVertexSource, const char* pFragmentSource) +{ + GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource); + if (!vertexShader) { + ALOGE("couldn't load the vertex shader!"); + return -1; + } + + GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource); + if (!pixelShader) { + ALOGE("couldn't load the pixel shader!"); + return -1; + } + + GLuint program = glCreateProgram(); + if (program) { + glAttachShader(program, vertexShader); + GLUtils::checkGlError("glAttachShader vertex"); + glAttachShader(program, pixelShader); + GLUtils::checkGlError("glAttachShader pixel"); + glLinkProgram(program); + GLint linkStatus = GL_FALSE; + glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); + if (linkStatus != GL_TRUE) { + GLint bufLength = 0; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); + if (bufLength) { + char* buf = (char*) malloc(bufLength); + if (buf) { + glGetProgramInfoLog(program, bufLength, 0, buf); + ALOGE("could not link program:\n%s\n", buf); + free(buf); + } + } + glDeleteProgram(program); + program = -1; + } + } + + ShaderResource newResource(program, vertexShader, pixelShader); + m_resources.append(newResource); + return program; +} + +ShaderProgram::ShaderProgram() + : m_blendingEnabled(false) + , m_contrast(1) + , m_alphaLayer(false) + , m_currentScale(1.0f) + , m_needsInit(true) +{ +} + +void ShaderProgram::cleanupGLResources() +{ + for (unsigned int i = 0; i < m_resources.size(); i++) { + glDetachShader(m_resources[i].program, m_resources[i].vertexShader); + glDetachShader(m_resources[i].program, m_resources[i].fragmentShader); + glDeleteShader(m_resources[i].vertexShader); + glDeleteShader(m_resources[i].fragmentShader); + glDeleteProgram(m_resources[i].program); + } + glDeleteBuffers(1, m_textureBuffer); + + m_resources.clear(); + m_needsInit = true; + GLUtils::checkGlError("cleanupGLResources"); + + return; +} + +void ShaderProgram::initGLResources() +{ + // To detect whether or not resources for ShaderProgram allocated + // successfully, we clean up pre-existing errors here and will check for + // new errors at the end of this function. + GLUtils::checkGlError("before initGLResources"); + + GLint tex2DProgram = createProgram(gVertexShader, gFragmentShader); + GLint pureColorProgram = createProgram(gPureColorVertexShader, gPureColorFragmentShader); + GLint tex2DInvProgram = createProgram(gVertexShader, gFragmentShaderInverted); + GLint videoProgram = createProgram(gVideoVertexShader, gVideoFragmentShader); + GLint texOESProgram = + createProgram(gVertexShader, gSurfaceTextureOESFragmentShader); + GLint texOESInvProgram = + createProgram(gVertexShader, gSurfaceTextureOESFragmentShaderInverted); + + if (tex2DProgram == -1 + || pureColorProgram == -1 + || tex2DInvProgram == -1 + || videoProgram == -1 + || texOESProgram == -1 + || texOESInvProgram == -1) { + m_needsInit = true; + return; + } + + GLint pureColorPosition = glGetAttribLocation(pureColorProgram, "vPosition"); + GLint pureColorProjMtx = glGetUniformLocation(pureColorProgram, "projectionMatrix"); + GLint pureColorValue = glGetUniformLocation(pureColorProgram, "inputColor"); + m_handleArray[PureColor].init(-1, -1, pureColorPosition, pureColorProgram, + pureColorProjMtx, pureColorValue, -1, -1); + + GLint tex2DAlpha = glGetUniformLocation(tex2DProgram, "alpha"); + GLint tex2DPosition = glGetAttribLocation(tex2DProgram, "vPosition"); + GLint tex2DProjMtx = glGetUniformLocation(tex2DProgram, "projectionMatrix"); + GLint tex2DTexSampler = glGetUniformLocation(tex2DProgram, "s_texture"); + m_handleArray[Tex2D].init(tex2DAlpha, -1, tex2DPosition, tex2DProgram, + tex2DProjMtx, -1, tex2DTexSampler, -1); + + GLint tex2DInvAlpha = glGetUniformLocation(tex2DInvProgram, "alpha"); + GLint tex2DInvContrast = glGetUniformLocation(tex2DInvProgram, "contrast"); + GLint tex2DInvPosition = glGetAttribLocation(tex2DInvProgram, "vPosition"); + GLint tex2DInvProjMtx = glGetUniformLocation(tex2DInvProgram, "projectionMatrix"); + GLint tex2DInvTexSampler = glGetUniformLocation(tex2DInvProgram, "s_texture"); + m_handleArray[Tex2DInv].init(tex2DInvAlpha, tex2DInvContrast, + tex2DInvPosition, tex2DInvProgram, + tex2DInvProjMtx, -1, + tex2DInvTexSampler, -1); + + GLint texOESAlpha = glGetUniformLocation(texOESProgram, "alpha"); + GLint texOESPosition = glGetAttribLocation(texOESProgram, "vPosition"); + GLint texOESProjMtx = glGetUniformLocation(texOESProgram, "projectionMatrix"); + GLint texOESTexSampler = glGetUniformLocation(texOESProgram, "s_texture"); + m_handleArray[TexOES].init(texOESAlpha, -1, texOESPosition, texOESProgram, + texOESProjMtx, -1, texOESTexSampler, -1); + + GLint texOESInvAlpha = glGetUniformLocation(texOESInvProgram, "alpha"); + GLint texOESInvContrast = glGetUniformLocation(texOESInvProgram, "contrast"); + GLint texOESInvPosition = glGetAttribLocation(texOESInvProgram, "vPosition"); + GLint texOESInvProjMtx = glGetUniformLocation(texOESInvProgram, "projectionMatrix"); + GLint texOESInvTexSampler = glGetUniformLocation(texOESInvProgram, "s_texture"); + m_handleArray[TexOESInv].init(texOESInvAlpha, texOESInvContrast, + texOESInvPosition, texOESInvProgram, + texOESInvProjMtx, -1, + texOESInvTexSampler, -1); + + GLint videoPosition = glGetAttribLocation(videoProgram, "vPosition"); + GLint videoProjMtx = glGetUniformLocation(videoProgram, "projectionMatrix"); + GLint videoTexSampler = glGetUniformLocation(videoProgram, "s_yuvTexture"); + GLint videoTexMtx = glGetUniformLocation(videoProgram, "textureMatrix"); + m_handleArray[Video].init(-1, -1, videoPosition, videoProgram, + videoProjMtx, -1, videoTexSampler, + videoTexMtx); + + const GLfloat coord[] = { + 0.0f, 0.0f, // C + 1.0f, 0.0f, // D + 0.0f, 1.0f, // A + 1.0f, 1.0f // B + }; + + glGenBuffers(1, m_textureBuffer); + glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]); + glBufferData(GL_ARRAY_BUFFER, 2 * 4 * sizeof(GLfloat), coord, GL_STATIC_DRAW); + + TransformationMatrix matrix; + // Map x,y from (0,1) to (-1, 1) + matrix.scale3d(2, 2, 1); + matrix.translate3d(-0.5, -0.5, 0); + GLUtils::toGLMatrix(m_transferProjMtx, matrix); + + m_needsInit = GLUtils::checkGlError("initGLResources"); + return; +} + +void ShaderProgram::resetBlending() +{ + glDisable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + glBlendEquation(GL_FUNC_ADD); + m_blendingEnabled = false; +} + +void ShaderProgram::setBlendingState(bool enableBlending) +{ + if (enableBlending == m_blendingEnabled) + return; + + if (enableBlending) + glEnable(GL_BLEND); + else + glDisable(GL_BLEND); + + m_blendingEnabled = enableBlending; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Drawing +///////////////////////////////////////////////////////////////////////////////////////// + +void ShaderProgram::setupDrawing(const IntRect& viewRect, const SkRect& visibleRect, + const IntRect& webViewRect, int titleBarHeight, + const IntRect& screenClip, float scale) +{ + m_webViewRect = webViewRect; + m_titleBarHeight = titleBarHeight; + + //// viewport //// + TransformationMatrix ortho; + GLUtils::setOrthographicMatrix(ortho, visibleRect.fLeft, visibleRect.fTop, + visibleRect.fRight, visibleRect.fBottom, -1000, 1000); + // In most case , visibleRect / viewRect * scale should 1.0, but for the + // translation case, the scale factor can be 1 but visibleRect is smaller + // than viewRect, we need to tune in this factor to make sure we scale them + // right. Conceptually, that means, no matter how animation affects the + // visibleRect, the scaling should respect the viewRect if zoomScale is 1.0. + // Note that at TiledPage, we already scale the tile size inversely to make + // zooming animation right. + float orthoScaleX = scale * visibleRect.width() / viewRect.width(); + float orthoScaleY = scale * visibleRect.height() / viewRect.height(); + + TransformationMatrix orthoScale; + orthoScale.scale3d(orthoScaleX, orthoScaleY, 1.0); + + m_projectionMatrix = ortho * orthoScale; + m_viewport = visibleRect; + m_currentScale = scale; + + + //// viewRect //// + m_viewRect = viewRect; + + // We do clipping using glScissor, which needs to take + // coordinates in screen space. The following matrix transform + // content coordinates in screen coordinates. + TransformationMatrix viewTranslate; + viewTranslate.translate(1.0, 1.0); + + TransformationMatrix viewScale; + viewScale.scale3d(m_viewRect.width() * 0.5f, m_viewRect.height() * 0.5f, 1); + + m_documentToScreenMatrix = viewScale * viewTranslate * m_projectionMatrix; + + viewTranslate.scale3d(1, -1, 1); + m_documentToInvScreenMatrix = viewScale * viewTranslate * m_projectionMatrix; + + IntRect rect(0, 0, m_webViewRect.width(), m_webViewRect.height()); + m_documentViewport = m_documentToScreenMatrix.inverse().mapRect(rect); + + + //// clipping //// + IntRect mclip = screenClip; + + // the clip from frameworks is in full screen coordinates + mclip.setY(screenClip.y() - m_webViewRect.y() - m_titleBarHeight); + FloatRect tclip = convertInvScreenCoordToScreenCoord(mclip); + m_screenClip.setLocation(IntPoint(tclip.x(), tclip.y())); + // use ceilf to handle view -> doc -> view coord rounding errors + m_screenClip.setSize(IntSize(ceilf(tclip.width()), ceilf(tclip.height()))); + + resetBlending(); +} + +// Calculate the right color value sent into the shader considering the (0,1) +// clamp and alpha blending. +Color ShaderProgram::shaderColor(Color pureColor, float opacity) +{ + float r = pureColor.red() / 255.0; + float g = pureColor.green() / 255.0; + float b = pureColor.blue() / 255.0; + float a = pureColor.alpha() / 255.0; + + if (TilesManager::instance()->invertedScreen()) { + float intensity = a - (0.2989 * r + 0.5866 * g + 0.1145 * b); + intensity = ((intensity - a / 2.0) * m_contrast) + a / 2.0; + intensity *= opacity; + return Color(intensity, intensity, intensity, a * opacity); + } + return Color(r * opacity, g * opacity, b * opacity, a * opacity); +} + +// For shaders using texture, it is easy to get the type from the textureTarget. +ShaderType ShaderProgram::getTextureShaderType(GLenum textureTarget) +{ + ShaderType type = UndefinedShader; + if (textureTarget == GL_TEXTURE_2D) { + if (!TilesManager::instance()->invertedScreen()) + type = Tex2D; + else { + // With the new GPU texture upload path, we do not use an FBO + // to blit the texture we receive from the TexturesGenerator thread. + // To implement inverted rendering, we thus have to do the rendering + // live, by using a different shader. + type = Tex2DInv; + } + } else if (textureTarget == GL_TEXTURE_EXTERNAL_OES) { + if (!TilesManager::instance()->invertedScreen()) + type = TexOES; + else + type = TexOESInv; + } + return type; +} + +// This function transform a clip rect extracted from the current layer +// into a clip rect in screen coordinates -- used by the clipping rects +FloatRect ShaderProgram::rectInScreenCoord(const TransformationMatrix& drawMatrix, const IntSize& size) +{ + FloatRect srect(0, 0, size.width(), size.height()); + TransformationMatrix renderMatrix = m_documentToScreenMatrix * drawMatrix; + return renderMatrix.mapRect(srect); +} + +// used by the partial screen invals +FloatRect ShaderProgram::rectInInvScreenCoord(const TransformationMatrix& drawMatrix, const IntSize& size) +{ + FloatRect srect(0, 0, size.width(), size.height()); + TransformationMatrix renderMatrix = m_documentToInvScreenMatrix * drawMatrix; + return renderMatrix.mapRect(srect); +} + +FloatRect ShaderProgram::rectInInvScreenCoord(const FloatRect& rect) +{ + return m_documentToInvScreenMatrix.mapRect(rect); +} + +FloatRect ShaderProgram::rectInScreenCoord(const FloatRect& rect) +{ + return m_documentToScreenMatrix.mapRect(rect); +} + +FloatRect ShaderProgram::convertScreenCoordToDocumentCoord(const FloatRect& rect) +{ + return m_documentToScreenMatrix.inverse().mapRect(rect); +} + +FloatRect ShaderProgram::convertInvScreenCoordToScreenCoord(const FloatRect& rect) +{ + FloatRect documentRect = m_documentToInvScreenMatrix.inverse().mapRect(rect); + return rectInScreenCoord(documentRect); +} + +FloatRect ShaderProgram::convertScreenCoordToInvScreenCoord(const FloatRect& rect) +{ + FloatRect documentRect = m_documentToScreenMatrix.inverse().mapRect(rect); + return rectInInvScreenCoord(documentRect); +} + +// clip is in screen coordinates +void ShaderProgram::clip(const FloatRect& clip) +{ + if (clip == m_clipRect) + return; + + ALOGV("--clipping rect %f %f, %f x %f", + clip.x(), clip.y(), clip.width(), clip.height()); + + // we should only call glScissor in this function, so that we can easily + // track the current clipping rect. + + IntRect screenClip(clip.x(), + clip.y(), + clip.width(), clip.height()); + + if (!m_screenClip.isEmpty()) + screenClip.intersect(m_screenClip); + + screenClip.setY(screenClip.y() + m_viewRect.y()); + if (screenClip.x() < 0) { + int w = screenClip.width(); + w += screenClip.x(); + screenClip.setX(0); + screenClip.setWidth(w); + } + if (screenClip.y() < 0) { + int h = screenClip.height(); + h += screenClip.y(); + screenClip.setY(0); + screenClip.setHeight(h); + } + + glScissor(screenClip.x(), screenClip.y(), screenClip.width(), screenClip.height()); + + m_clipRect = clip; +} + +IntRect ShaderProgram::clippedRectWithViewport(const IntRect& rect, int margin) +{ + IntRect viewport(m_viewport.fLeft - margin, m_viewport.fTop - margin, + m_viewport.width() + margin, m_viewport.height() + margin); + viewport.intersect(rect); + return viewport; +} + +float ShaderProgram::zValue(const TransformationMatrix& drawMatrix, float w, float h) +{ + TransformationMatrix modifiedDrawMatrix = drawMatrix; + modifiedDrawMatrix.scale3d(w, h, 1); + TransformationMatrix renderMatrix = m_projectionMatrix * modifiedDrawMatrix; + FloatPoint3D point(0.5, 0.5, 0.0); + FloatPoint3D result = renderMatrix.mapPoint(point); + return result.z(); +} + +void ShaderProgram::drawQuadInternal(ShaderType type, const GLfloat* matrix, + int textureId, float opacity, + GLenum textureTarget, GLenum filter, + const Color& pureColor) +{ + glUseProgram(m_handleArray[type].programHandle); + glUniformMatrix4fv(m_handleArray[type].projMtxHandle, 1, GL_FALSE, matrix); + + if (type != PureColor) { + glActiveTexture(GL_TEXTURE0); + glUniform1i(m_handleArray[type].texSamplerHandle, 0); + glBindTexture(textureTarget, textureId); + glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, filter); + glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, filter); + glUniform1f(m_handleArray[type].alphaHandle, opacity); + + GLint contrastHandle = m_handleArray[type].contrastHandle; + if (contrastHandle != -1) + glUniform1f(contrastHandle, m_contrast); + } else { + glUniform4f(m_handleArray[type].pureColorHandle, + pureColor.red() / 255.0, pureColor.green() / 255.0, + pureColor.blue() / 255.0, pureColor.alpha() / 255.0); + } + + GLint positionHandle = m_handleArray[type].positionHandle; + glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]); + glEnableVertexAttribArray(positionHandle); + glVertexAttribPointer(positionHandle, 2, GL_FLOAT, GL_FALSE, 0, 0); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); +} + +// Calculate the matrix given the geometry. +GLfloat* ShaderProgram::getProjectionMatrix(const DrawQuadData* data) +{ + DrawQuadType type = data->type(); + const TransformationMatrix* matrix = data->drawMatrix(); + const SkRect* geometry = data->geometry(); + if (type == Blit) + return m_transferProjMtx; + TransformationMatrix modifiedDrawMatrix; + if (type == LayerQuad) + modifiedDrawMatrix = *matrix; + // move the drawing depending on where the texture is on the layer + modifiedDrawMatrix.translate(geometry->fLeft, geometry->fTop); + modifiedDrawMatrix.scale3d(geometry->width(), geometry->height(), 1); + + TransformationMatrix renderMatrix; + if (!m_alphaLayer) + renderMatrix = m_projectionMatrix * m_repositionMatrix + * m_webViewMatrix * modifiedDrawMatrix; + else + renderMatrix = m_projectionMatrix * modifiedDrawMatrix; + + GLUtils::toGLMatrix(m_tileProjMatrix, renderMatrix); + return m_tileProjMatrix; +} + +void ShaderProgram::drawQuad(const DrawQuadData* data) +{ + GLfloat* matrix = getProjectionMatrix(data); + + float opacity = data->opacity(); + bool forceBlending = data->forceBlending(); + bool enableBlending = forceBlending || opacity < 1.0; + + ShaderType shaderType = UndefinedShader; + int textureId = 0; + GLint textureFilter = 0; + GLenum textureTarget = 0; + + Color quadColor = data->quadColor(); + if (data->pureColor()) { + shaderType = PureColor; + quadColor = shaderColor(quadColor, opacity); + enableBlending = enableBlending || quadColor.hasAlpha(); + if (!quadColor.alpha() && enableBlending) + return; + } else { + textureId = data->textureId(); + textureFilter = data->textureFilter(); + textureTarget = data->textureTarget(); + shaderType = getTextureShaderType(textureTarget); + } + setBlendingState(enableBlending); + drawQuadInternal(shaderType, matrix, textureId, opacity, + textureTarget, textureFilter, quadColor); +} + +void ShaderProgram::drawVideoLayerQuad(const TransformationMatrix& drawMatrix, + float* textureMatrix, SkRect& geometry, + int textureId) +{ + // switch to our custom yuv video rendering program + glUseProgram(m_handleArray[Video].programHandle); + + TransformationMatrix modifiedDrawMatrix = drawMatrix; + modifiedDrawMatrix.translate(geometry.fLeft, geometry.fTop); + modifiedDrawMatrix.scale3d(geometry.width(), geometry.height(), 1); + TransformationMatrix renderMatrix = m_projectionMatrix * modifiedDrawMatrix; + + GLfloat projectionMatrix[16]; + GLUtils::toGLMatrix(projectionMatrix, renderMatrix); + glUniformMatrix4fv(m_handleArray[Video].projMtxHandle, 1, GL_FALSE, + projectionMatrix); + glUniformMatrix4fv(m_handleArray[Video].videoMtxHandle, 1, GL_FALSE, + textureMatrix); + + glActiveTexture(GL_TEXTURE0); + glUniform1i(m_handleArray[Video].texSamplerHandle, 0); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureId); + + GLint videoPosition = m_handleArray[Video].positionHandle; + glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]); + glEnableVertexAttribArray(videoPosition); + glVertexAttribPointer(videoPosition, 2, GL_FLOAT, GL_FALSE, 0, 0); + + setBlendingState(false); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); +} + +void ShaderProgram::setWebViewMatrix(const float* matrix, bool alphaLayer) +{ + GLUtils::convertToTransformationMatrix(matrix, m_webViewMatrix); + m_alphaLayer = alphaLayer; +} + +void ShaderProgram::calculateAnimationDelta() +{ + // The matrix contains the scrolling info, so this rect is starting from + // the m_viewport. + // So we just need to map the webview's visible rect using the matrix, + // calculate the difference b/t transformed rect and the webViewRect, + // then we can get the delta x , y caused by the animation. + // Note that the Y is for reporting back to GL viewport, so it is inverted. + // When it is alpha animation, then we rely on the framework implementation + // such that there is no matrix applied in native webkit. + if (!m_alphaLayer) { + FloatRect rect(m_viewport.fLeft * m_currentScale, + m_viewport.fTop * m_currentScale, + m_webViewRect.width(), + m_webViewRect.height()); + rect = m_webViewMatrix.mapRect(rect); + m_animationDelta.setX(rect.x() - m_webViewRect.x() ); + m_animationDelta.setY(rect.y() + rect.height() - m_webViewRect.y() + - m_webViewRect.height() - m_titleBarHeight); + + m_repositionMatrix.makeIdentity(); + m_repositionMatrix.translate3d(-m_webViewRect.x(), -m_webViewRect.y() - m_titleBarHeight, 0); + m_repositionMatrix.translate3d(m_viewport.fLeft * m_currentScale, m_viewport.fTop * m_currentScale, 0); + m_repositionMatrix.translate3d(-m_animationDelta.x(), -m_animationDelta.y(), 0); + } else { + m_animationDelta.setX(0); + m_animationDelta.setY(0); + m_repositionMatrix.makeIdentity(); + } + +} + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) |