2 * Copyright 2010, The Android Open Source Project
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "ShaderProgram.h"
29 #if USE(ACCELERATED_COMPOSITING)
31 #include "FloatPoint3D.h"
33 #include "TilesManager.h"
35 #include <GLES2/gl2.h>
36 #include <GLES2/gl2ext.h>
37 #include <cutils/log.h>
38 #include <wtf/CurrentTime.h>
39 #include <wtf/text/CString.h>
42 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "ShaderProgram", __VA_ARGS__)
46 static const char gVertexShader[] =
47 "attribute vec4 vPosition;\n"
48 "uniform mat4 projectionMatrix;\n"
49 "varying vec2 v_texCoord;\n"
51 " gl_Position = projectionMatrix * vPosition;\n"
52 " v_texCoord = vec2(vPosition);\n"
55 static const char gFragmentShader[] =
56 "precision mediump float;\n"
57 "varying vec2 v_texCoord; \n"
58 "uniform float alpha; \n"
59 "uniform sampler2D s_texture; \n"
61 " gl_FragColor = texture2D(s_texture, v_texCoord); \n"
62 " gl_FragColor *= alpha; "
65 static const char gVideoVertexShader[] =
66 "attribute vec4 vPosition;\n"
67 "uniform mat4 textureMatrix;\n"
68 "uniform mat4 projectionMatrix;\n"
69 "varying vec2 v_texCoord;\n"
71 " gl_Position = projectionMatrix * vPosition;\n"
72 " v_texCoord = vec2(textureMatrix * vec4(vPosition.x, 1.0 - vPosition.y, 0.0, 1.0));\n"
75 static const char gVideoFragmentShader[] =
76 "#extension GL_OES_EGL_image_external : require\n"
77 "precision mediump float;\n"
78 "uniform samplerExternalOES s_yuvTexture;\n"
79 "varying vec2 v_texCoord;\n"
81 " gl_FragColor = texture2D(s_yuvTexture, v_texCoord);\n"
84 static const char gSurfaceTextureOESFragmentShader[] =
85 "#extension GL_OES_EGL_image_external : require\n"
86 "precision mediump float;\n"
87 "varying vec2 v_texCoord; \n"
88 "uniform float alpha; \n"
89 "uniform samplerExternalOES s_texture; \n"
91 " gl_FragColor = texture2D(s_texture, v_texCoord); \n"
92 " gl_FragColor *= alpha; "
95 static const char gSurfaceTextureOESFragmentShaderInverted[] =
96 "#extension GL_OES_EGL_image_external : require\n"
97 "precision mediump float;\n"
98 "varying vec2 v_texCoord; \n"
99 "uniform float alpha; \n"
100 "uniform float contrast; \n"
101 "uniform samplerExternalOES s_texture; \n"
103 " vec4 pixel = texture2D(s_texture, v_texCoord); \n"
104 " float a = pixel.a; \n"
105 " float color = a - (0.2989 * pixel.r + 0.5866 * pixel.g + 0.1145 * pixel.b);\n"
106 " color = ((color - a/2.0) * contrast) + a/2.0; \n"
107 " pixel.rgb = vec3(color, color, color); \n "
108 " gl_FragColor = pixel; \n"
109 " gl_FragColor *= alpha; \n"
112 GLuint ShaderProgram::loadShader(GLenum shaderType, const char* pSource)
114 GLuint shader = glCreateShader(shaderType);
116 glShaderSource(shader, 1, &pSource, 0);
117 glCompileShader(shader);
119 glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
122 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
124 char* buf = (char*) malloc(infoLen);
126 glGetShaderInfoLog(shader, infoLen, 0, buf);
127 XLOG("could not compile shader %d:\n%s\n", shaderType, buf);
130 glDeleteShader(shader);
138 GLuint ShaderProgram::createProgram(const char* pVertexSource, const char* pFragmentSource)
140 GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
142 XLOG("couldn't load the vertex shader!");
146 GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
148 XLOG("couldn't load the pixel shader!");
152 GLuint program = glCreateProgram();
154 glAttachShader(program, vertexShader);
155 GLUtils::checkGlError("glAttachShader vertex");
156 glAttachShader(program, pixelShader);
157 GLUtils::checkGlError("glAttachShader pixel");
158 glLinkProgram(program);
159 GLint linkStatus = GL_FALSE;
160 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
161 if (linkStatus != GL_TRUE) {
163 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
165 char* buf = (char*) malloc(bufLength);
167 glGetProgramInfoLog(program, bufLength, 0, buf);
168 XLOG("could not link program:\n%s\n", buf);
172 glDeleteProgram(program);
179 ShaderProgram::ShaderProgram()
180 : m_blendingEnabled(false)
186 void ShaderProgram::init()
188 m_program = createProgram(gVertexShader, gFragmentShader);
189 m_videoProgram = createProgram(gVideoVertexShader, gVideoFragmentShader);
190 m_surfTexOESProgram =
191 createProgram(gVertexShader, gSurfaceTextureOESFragmentShader);
192 m_surfTexOESProgramInverted =
193 createProgram(gVertexShader, gSurfaceTextureOESFragmentShaderInverted);
196 || m_videoProgram == -1
197 || m_surfTexOESProgram == -1
198 || m_surfTexOESProgramInverted == -1)
201 m_hProjectionMatrix = glGetUniformLocation(m_program, "projectionMatrix");
202 m_hAlpha = glGetUniformLocation(m_program, "alpha");
203 m_hTexSampler = glGetUniformLocation(m_program, "s_texture");
204 m_hPosition = glGetAttribLocation(m_program, "vPosition");
206 m_hVideoProjectionMatrix =
207 glGetUniformLocation(m_videoProgram, "projectionMatrix");
208 m_hVideoTextureMatrix = glGetUniformLocation(m_videoProgram, "textureMatrix");
209 m_hVideoTexSampler = glGetUniformLocation(m_videoProgram, "s_yuvTexture");
210 m_hVideoPosition = glGetAttribLocation(m_program, "vPosition");
212 m_hSTOESProjectionMatrix =
213 glGetUniformLocation(m_surfTexOESProgram, "projectionMatrix");
214 m_hSTOESAlpha = glGetUniformLocation(m_surfTexOESProgram, "alpha");
215 m_hSTOESTexSampler = glGetUniformLocation(m_surfTexOESProgram, "s_texture");
216 m_hSTOESPosition = glGetAttribLocation(m_surfTexOESProgram, "vPosition");
218 m_hSTOESProjectionMatrixInverted =
219 glGetUniformLocation(m_surfTexOESProgramInverted, "projectionMatrix");
220 m_hSTOESAlphaInverted = glGetUniformLocation(m_surfTexOESProgramInverted, "alpha");
221 m_hSTOESContrastInverted = glGetUniformLocation(m_surfTexOESProgramInverted, "contrast");
222 m_hSTOESTexSamplerInverted = glGetUniformLocation(m_surfTexOESProgramInverted, "s_texture");
223 m_hSTOESPositionInverted = glGetAttribLocation(m_surfTexOESProgramInverted, "vPosition");
226 const GLfloat coord[] = {
233 glGenBuffers(1, m_textureBuffer);
234 glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]);
235 glBufferData(GL_ARRAY_BUFFER, 2 * 4 * sizeof(GLfloat), coord, GL_STATIC_DRAW);
237 GLUtils::checkGlError("init");
240 void ShaderProgram::resetBlending()
243 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
244 glBlendEquation(GL_FUNC_ADD);
245 m_blendingEnabled = false;
248 void ShaderProgram::setBlendingState(bool enableBlending)
250 if (enableBlending == m_blendingEnabled)
258 m_blendingEnabled = enableBlending;
261 /////////////////////////////////////////////////////////////////////////////////////////
263 /////////////////////////////////////////////////////////////////////////////////////////
265 void ShaderProgram::setViewport(SkRect& viewport)
267 TransformationMatrix ortho;
268 GLUtils::setOrthographicMatrix(ortho, viewport.fLeft, viewport.fTop,
269 viewport.fRight, viewport.fBottom, -1000, 1000);
270 m_projectionMatrix = ortho;
271 m_viewport = viewport;
274 void ShaderProgram::setProjectionMatrix(SkRect& geometry, GLint projectionMatrixHandle)
276 TransformationMatrix translate;
277 translate.translate3d(geometry.fLeft, geometry.fTop, 0.0);
278 TransformationMatrix scale;
279 scale.scale3d(geometry.width(), geometry.height(), 1.0);
281 TransformationMatrix total = m_projectionMatrix * translate * scale;
283 GLfloat projectionMatrix[16];
284 GLUtils::toGLMatrix(projectionMatrix, total);
285 glUniformMatrix4fv(projectionMatrixHandle, 1, GL_FALSE, projectionMatrix);
288 void ShaderProgram::drawQuadInternal(SkRect& geometry,
292 GLint projectionMatrixHandle,
294 GLenum textureTarget,
300 glUseProgram(program);
302 if (!geometry.isEmpty())
303 setProjectionMatrix(geometry, projectionMatrixHandle);
305 TransformationMatrix matrix;
306 // Map x,y from (0,1) to (-1, 1)
307 matrix.scale3d(2, 2, 1);
308 matrix.translate3d(-0.5, -0.5, 0);
309 GLfloat projectionMatrix[16];
310 GLUtils::toGLMatrix(projectionMatrix, matrix);
311 glUniformMatrix4fv(projectionMatrixHandle, 1, GL_FALSE, projectionMatrix);
314 glActiveTexture(GL_TEXTURE0);
315 glUniform1i(texSampler, 0);
316 glBindTexture(textureTarget, textureId);
317 glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
318 glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
319 glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
320 glTexParameteri(textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
322 glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]);
323 glEnableVertexAttribArray(position);
324 glVertexAttribPointer(position, 2, GL_FLOAT, GL_FALSE, 0, 0);
325 glUniform1f(alpha, opacity);
327 glUniform1f(contrast, m_contrast);
329 setBlendingState(opacity < 1.0);
330 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
333 void ShaderProgram::drawQuad(SkRect& geometry, int textureId, float opacity,
334 GLenum textureTarget, GLint texFilter)
336 if (textureTarget == GL_TEXTURE_2D) {
337 drawQuadInternal(geometry, textureId, opacity, m_program,
339 m_hTexSampler, GL_TEXTURE_2D,
340 m_hPosition, alpha(), texFilter);
341 } else if (textureTarget == GL_TEXTURE_EXTERNAL_OES
342 && !TilesManager::instance()->invertedScreen()) {
343 drawQuadInternal(geometry, textureId, opacity, m_surfTexOESProgram,
344 m_hSTOESProjectionMatrix,
345 m_hSTOESTexSampler, GL_TEXTURE_EXTERNAL_OES,
346 m_hSTOESPosition, m_hSTOESAlpha, texFilter);
347 } else if (textureTarget == GL_TEXTURE_EXTERNAL_OES
348 && TilesManager::instance()->invertedScreen()) {
349 drawQuadInternal(geometry, textureId, opacity, m_surfTexOESProgramInverted,
350 m_hSTOESProjectionMatrixInverted,
351 m_hSTOESTexSamplerInverted, GL_TEXTURE_EXTERNAL_OES,
352 m_hSTOESPositionInverted, m_hSTOESAlphaInverted,
353 texFilter, m_hSTOESContrastInverted);
355 GLUtils::checkGlError("drawQuad");
358 void ShaderProgram::setViewRect(const IntRect& viewRect)
360 m_viewRect = viewRect;
362 // We do clipping using glScissor, which needs to take
363 // coordinates in screen space. The following matrix transform
364 // content coordinates in screen coordinates.
365 TransformationMatrix translate;
366 translate.translate(1.0, 1.0);
368 TransformationMatrix scale;
369 scale.scale3d(m_viewRect.width() * 0.5f, m_viewRect.height() * 0.5f, 1);
371 m_documentToScreenMatrix = scale * translate * m_projectionMatrix;
373 translate.scale3d(1, -1, 1);
374 m_documentToInvScreenMatrix = scale * translate * m_projectionMatrix;
377 // This function transform a clip rect extracted from the current layer
378 // into a clip rect in screen coordinates -- used by the clipping rects
379 FloatRect ShaderProgram::rectInScreenCoord(const TransformationMatrix& drawMatrix, const IntSize& size)
381 FloatRect srect(0, 0, size.width(), size.height());
382 TransformationMatrix renderMatrix = m_documentToScreenMatrix * drawMatrix;
383 return renderMatrix.mapRect(srect);
386 // used by the partial screen invals
387 FloatRect ShaderProgram::rectInInvScreenCoord(const TransformationMatrix& drawMatrix, const IntSize& size)
389 FloatRect srect(0, 0, size.width(), size.height());
390 TransformationMatrix renderMatrix = m_documentToInvScreenMatrix * drawMatrix;
391 return renderMatrix.mapRect(srect);
394 FloatRect ShaderProgram::rectInInvScreenCoord(const FloatRect& rect)
396 return m_documentToInvScreenMatrix.mapRect(rect);
399 FloatRect ShaderProgram::rectInScreenCoord(const FloatRect& rect)
401 return m_documentToScreenMatrix.mapRect(rect);
404 FloatRect ShaderProgram::convertInvScreenCoordToScreenCoord(const FloatRect& rect)
406 FloatRect documentRect = m_documentToInvScreenMatrix.inverse().mapRect(rect);
407 return rectInScreenCoord(documentRect);
410 FloatRect ShaderProgram::convertScreenCoordToInvScreenCoord(const FloatRect& rect)
412 FloatRect documentRect = m_documentToScreenMatrix.inverse().mapRect(rect);
413 return rectInInvScreenCoord(documentRect);
416 void ShaderProgram::setScreenClip(const IntRect& clip)
419 IntRect mclip = clip;
421 // the clip from frameworks is in full screen coordinates
422 mclip.setY(clip.y() - m_webViewRect.y() - m_titleBarHeight);
423 FloatRect tclip = convertInvScreenCoordToScreenCoord(mclip);
424 IntRect screenClip(tclip.x(), tclip.y(), tclip.width(), tclip.height());
425 m_screenClip = screenClip;
428 // clip is in screen coordinates
429 void ShaderProgram::clip(const FloatRect& clip)
431 if (clip == m_clipRect)
434 // we should only call glScissor in this function, so that we can easily
435 // track the current clipping rect.
437 IntRect screenClip(clip.x(),
439 clip.width(), clip.height());
441 if (!m_screenClip.isEmpty())
442 screenClip.intersect(m_screenClip);
444 screenClip.setY(screenClip.y() + m_viewRect.y());
445 if (screenClip.x() < 0) {
446 int w = screenClip.width();
449 screenClip.setWidth(w);
451 if (screenClip.y() < 0) {
452 int h = screenClip.height();
455 screenClip.setHeight(h);
458 glScissor(screenClip.x(), screenClip.y(), screenClip.width(), screenClip.height());
463 IntRect ShaderProgram::clippedRectWithViewport(const IntRect& rect, int margin)
465 IntRect viewport(m_viewport.fLeft - margin, m_viewport.fTop - margin,
466 m_viewport.width() + margin, m_viewport.height() + margin);
467 viewport.intersect(rect);
471 float ShaderProgram::zValue(const TransformationMatrix& drawMatrix, float w, float h)
473 TransformationMatrix modifiedDrawMatrix = drawMatrix;
474 modifiedDrawMatrix.scale3d(w, h, 1);
475 TransformationMatrix renderMatrix = m_projectionMatrix * modifiedDrawMatrix;
476 FloatPoint3D point(0.5, 0.5, 0.0);
477 FloatPoint3D result = renderMatrix.mapPoint(point);
481 void ShaderProgram::drawLayerQuadInternal(const GLfloat* projectionMatrix,
482 int textureId, float opacity,
483 GLenum textureTarget, GLint program,
484 GLint matrix, GLint texSample,
485 GLint position, GLint alpha,
488 glUseProgram(program);
489 glUniformMatrix4fv(matrix, 1, GL_FALSE, projectionMatrix);
491 glActiveTexture(GL_TEXTURE0);
492 glUniform1i(texSample, 0);
493 glBindTexture(textureTarget, textureId);
494 glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
495 glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
496 glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
497 glTexParameteri(textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
500 glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]);
501 glEnableVertexAttribArray(position);
502 glVertexAttribPointer(position, 2, GL_FLOAT, GL_FALSE, 0, 0);
503 glUniform1f(alpha, opacity);
505 glUniform1f(contrast, m_contrast);
509 void ShaderProgram::drawLayerQuad(const TransformationMatrix& drawMatrix,
510 SkRect& geometry, int textureId, float opacity,
511 bool forceBlending, GLenum textureTarget)
514 TransformationMatrix modifiedDrawMatrix = drawMatrix;
515 // move the drawing depending on where the texture is on the layer
516 modifiedDrawMatrix.translate(geometry.fLeft, geometry.fTop);
517 modifiedDrawMatrix.scale3d(geometry.width(), geometry.height(), 1);
518 TransformationMatrix renderMatrix = m_projectionMatrix * modifiedDrawMatrix;
520 GLfloat projectionMatrix[16];
521 GLUtils::toGLMatrix(projectionMatrix, renderMatrix);
522 if (textureTarget == GL_TEXTURE_2D) {
523 drawLayerQuadInternal(projectionMatrix, textureId, opacity,
524 GL_TEXTURE_2D, m_program,
525 m_hProjectionMatrix, m_hTexSampler,
526 m_hPosition, alpha());
527 } else if (textureTarget == GL_TEXTURE_EXTERNAL_OES
528 && !TilesManager::instance()->invertedScreen()) {
529 drawLayerQuadInternal(projectionMatrix, textureId, opacity,
530 GL_TEXTURE_EXTERNAL_OES, m_surfTexOESProgram,
531 m_hSTOESProjectionMatrix, m_hSTOESTexSampler,
532 m_hSTOESPosition, m_hSTOESAlpha);
533 } else if (textureTarget == GL_TEXTURE_EXTERNAL_OES
534 && TilesManager::instance()->invertedScreen()) {
535 drawLayerQuadInternal(projectionMatrix, textureId, opacity,
536 GL_TEXTURE_EXTERNAL_OES, m_surfTexOESProgramInverted,
537 m_hSTOESProjectionMatrixInverted, m_hSTOESTexSamplerInverted,
538 m_hSTOESPositionInverted, m_hSTOESAlphaInverted,
539 m_hSTOESContrastInverted);
542 setBlendingState(forceBlending || opacity < 1.0);
543 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
545 GLUtils::checkGlError("drawLayerQuad");
548 void ShaderProgram::drawVideoLayerQuad(const TransformationMatrix& drawMatrix,
549 float* textureMatrix, SkRect& geometry,
552 // switch to our custom yuv video rendering program
553 glUseProgram(m_videoProgram);
555 TransformationMatrix modifiedDrawMatrix = drawMatrix;
556 modifiedDrawMatrix.translate(geometry.fLeft, geometry.fTop);
557 modifiedDrawMatrix.scale3d(geometry.width(), geometry.height(), 1);
558 TransformationMatrix renderMatrix = m_projectionMatrix * modifiedDrawMatrix;
560 GLfloat projectionMatrix[16];
561 GLUtils::toGLMatrix(projectionMatrix, renderMatrix);
562 glUniformMatrix4fv(m_hVideoProjectionMatrix, 1, GL_FALSE, projectionMatrix);
563 glUniformMatrix4fv(m_hVideoTextureMatrix, 1, GL_FALSE, textureMatrix);
565 glActiveTexture(GL_TEXTURE0);
566 glUniform1i(m_hVideoTexSampler, 0);
567 glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureId);
569 glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]);
570 glEnableVertexAttribArray(m_hVideoPosition);
571 glVertexAttribPointer(m_hVideoPosition, 2, GL_FLOAT, GL_FALSE, 0, 0);
573 setBlendingState(false);
574 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
577 } // namespace WebCore
579 #endif // USE(ACCELERATED_COMPOSITING)