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,
299 glUseProgram(program);
301 if (!geometry.isEmpty())
302 setProjectionMatrix(geometry, projectionMatrixHandle);
304 TransformationMatrix matrix;
305 // Map x,y from (0,1) to (-1, 1)
306 matrix.scale3d(2, 2, 1);
307 matrix.translate3d(-0.5, -0.5, 0);
308 GLfloat projectionMatrix[16];
309 GLUtils::toGLMatrix(projectionMatrix, matrix);
310 glUniformMatrix4fv(projectionMatrixHandle, 1, GL_FALSE, projectionMatrix);
313 glActiveTexture(GL_TEXTURE0);
314 glUniform1i(texSampler, 0);
315 glBindTexture(textureTarget, textureId);
316 glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
317 glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
318 glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
319 glTexParameteri(textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
321 glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]);
322 glEnableVertexAttribArray(position);
323 glVertexAttribPointer(position, 2, GL_FLOAT, GL_FALSE, 0, 0);
324 glUniform1f(alpha, opacity);
326 glUniform1f(contrast, m_contrast);
328 setBlendingState(opacity < 1.0);
329 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
332 void ShaderProgram::drawQuad(SkRect& geometry, int textureId, float opacity,
333 GLenum textureTarget)
335 if (textureTarget == GL_TEXTURE_2D) {
336 drawQuadInternal(geometry, textureId, opacity, m_program,
338 m_hTexSampler, GL_TEXTURE_2D,
339 m_hPosition, alpha());
340 } else if (textureTarget == GL_TEXTURE_EXTERNAL_OES
341 && !TilesManager::instance()->invertedScreen()) {
342 drawQuadInternal(geometry, textureId, opacity, m_surfTexOESProgram,
343 m_hSTOESProjectionMatrix,
344 m_hSTOESTexSampler, GL_TEXTURE_EXTERNAL_OES,
345 m_hSTOESPosition, m_hSTOESAlpha);
346 } else if (textureTarget == GL_TEXTURE_EXTERNAL_OES
347 && TilesManager::instance()->invertedScreen()) {
348 drawQuadInternal(geometry, textureId, opacity, m_surfTexOESProgramInverted,
349 m_hSTOESProjectionMatrixInverted,
350 m_hSTOESTexSamplerInverted, GL_TEXTURE_EXTERNAL_OES,
351 m_hSTOESPositionInverted, m_hSTOESAlphaInverted,
352 m_hSTOESContrastInverted);
354 GLUtils::checkGlError("drawQuad");
357 void ShaderProgram::setViewRect(const IntRect& viewRect)
359 m_viewRect = viewRect;
361 // We do clipping using glScissor, which needs to take
362 // coordinates in screen space. The following matrix transform
363 // content coordinates in screen coordinates.
364 TransformationMatrix translate;
365 translate.translate(1.0, 1.0);
367 TransformationMatrix scale;
368 scale.scale3d(m_viewRect.width() * 0.5f, m_viewRect.height() * 0.5f, 1);
370 m_documentToScreenMatrix = scale * translate * m_projectionMatrix;
372 translate.scale3d(1, -1, 1);
373 m_documentToInvScreenMatrix = scale * translate * m_projectionMatrix;
376 // This function transform a clip rect extracted from the current layer
377 // into a clip rect in screen coordinates -- used by the clipping rects
378 FloatRect ShaderProgram::rectInScreenCoord(const TransformationMatrix& drawMatrix, const IntSize& size)
380 FloatRect srect(0, 0, size.width(), size.height());
381 TransformationMatrix renderMatrix = m_documentToScreenMatrix * drawMatrix;
382 return renderMatrix.mapRect(srect);
385 // used by the partial screen invals
386 FloatRect ShaderProgram::rectInInvScreenCoord(const TransformationMatrix& drawMatrix, const IntSize& size)
388 FloatRect srect(0, 0, size.width(), size.height());
389 TransformationMatrix renderMatrix = m_documentToInvScreenMatrix * drawMatrix;
390 return renderMatrix.mapRect(srect);
393 FloatRect ShaderProgram::rectInInvScreenCoord(const FloatRect& rect)
395 return m_documentToInvScreenMatrix.mapRect(rect);
398 FloatRect ShaderProgram::rectInScreenCoord(const FloatRect& rect)
400 return m_documentToScreenMatrix.mapRect(rect);
403 FloatRect ShaderProgram::convertInvScreenCoordToScreenCoord(const FloatRect& rect)
405 FloatRect documentRect = m_documentToInvScreenMatrix.inverse().mapRect(rect);
406 return rectInScreenCoord(documentRect);
409 FloatRect ShaderProgram::convertScreenCoordToInvScreenCoord(const FloatRect& rect)
411 FloatRect documentRect = m_documentToScreenMatrix.inverse().mapRect(rect);
412 return rectInInvScreenCoord(documentRect);
415 void ShaderProgram::setScreenClip(const IntRect& clip)
418 IntRect mclip = clip;
420 // the clip from frameworks is in full screen coordinates
421 mclip.setY(clip.y() - m_webViewRect.y() - m_titleBarHeight);
422 FloatRect tclip = convertInvScreenCoordToScreenCoord(mclip);
423 IntRect screenClip(tclip.x(), tclip.y(), tclip.width(), tclip.height());
424 m_screenClip = screenClip;
427 // clip is in screen coordinates
428 void ShaderProgram::clip(const FloatRect& clip)
430 if (clip == m_clipRect)
433 // we should only call glScissor in this function, so that we can easily
434 // track the current clipping rect.
436 IntRect screenClip(clip.x(),
438 clip.width(), clip.height());
440 if (!m_screenClip.isEmpty())
441 screenClip.intersect(m_screenClip);
443 screenClip.setY(screenClip.y() + m_viewRect.y());
444 if (screenClip.x() < 0) {
445 int w = screenClip.width();
448 screenClip.setWidth(w);
450 if (screenClip.y() < 0) {
451 int h = screenClip.height();
454 screenClip.setHeight(h);
457 glScissor(screenClip.x(), screenClip.y(), screenClip.width(), screenClip.height());
462 IntRect ShaderProgram::clippedRectWithViewport(const IntRect& rect, int margin)
464 IntRect viewport(m_viewport.fLeft - margin, m_viewport.fTop - margin,
465 m_viewport.width() + margin, m_viewport.height() + margin);
466 viewport.intersect(rect);
470 float ShaderProgram::zValue(const TransformationMatrix& drawMatrix, float w, float h)
472 TransformationMatrix modifiedDrawMatrix = drawMatrix;
473 modifiedDrawMatrix.scale3d(w, h, 1);
474 TransformationMatrix renderMatrix = m_projectionMatrix * modifiedDrawMatrix;
475 FloatPoint3D point(0.5, 0.5, 0.0);
476 FloatPoint3D result = renderMatrix.mapPoint(point);
480 void ShaderProgram::drawLayerQuadInternal(const GLfloat* projectionMatrix,
481 int textureId, float opacity,
482 GLenum textureTarget, GLint program,
483 GLint matrix, GLint texSample,
484 GLint position, GLint alpha,
487 glUseProgram(program);
488 glUniformMatrix4fv(matrix, 1, GL_FALSE, projectionMatrix);
490 glActiveTexture(GL_TEXTURE0);
491 glUniform1i(texSample, 0);
492 glBindTexture(textureTarget, textureId);
493 glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
494 glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
495 glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
496 glTexParameteri(textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
499 glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]);
500 glEnableVertexAttribArray(position);
501 glVertexAttribPointer(position, 2, GL_FLOAT, GL_FALSE, 0, 0);
502 glUniform1f(alpha, opacity);
504 glUniform1f(contrast, m_contrast);
508 void ShaderProgram::drawLayerQuad(const TransformationMatrix& drawMatrix,
509 SkRect& geometry, int textureId, float opacity,
510 bool forceBlending, GLenum textureTarget)
513 TransformationMatrix modifiedDrawMatrix = drawMatrix;
514 // move the drawing depending on where the texture is on the layer
515 modifiedDrawMatrix.translate(geometry.fLeft, geometry.fTop);
516 modifiedDrawMatrix.scale3d(geometry.width(), geometry.height(), 1);
517 TransformationMatrix renderMatrix = m_projectionMatrix * modifiedDrawMatrix;
519 GLfloat projectionMatrix[16];
520 GLUtils::toGLMatrix(projectionMatrix, renderMatrix);
521 if (textureTarget == GL_TEXTURE_2D) {
522 drawLayerQuadInternal(projectionMatrix, textureId, opacity,
523 GL_TEXTURE_2D, m_program,
524 m_hProjectionMatrix, m_hTexSampler,
525 m_hPosition, alpha());
526 } else if (textureTarget == GL_TEXTURE_EXTERNAL_OES
527 && !TilesManager::instance()->invertedScreen()) {
528 drawLayerQuadInternal(projectionMatrix, textureId, opacity,
529 GL_TEXTURE_EXTERNAL_OES, m_surfTexOESProgram,
530 m_hSTOESProjectionMatrix, m_hSTOESTexSampler,
531 m_hSTOESPosition, m_hSTOESAlpha);
532 } else if (textureTarget == GL_TEXTURE_EXTERNAL_OES
533 && TilesManager::instance()->invertedScreen()) {
534 drawLayerQuadInternal(projectionMatrix, textureId, opacity,
535 GL_TEXTURE_EXTERNAL_OES, m_surfTexOESProgramInverted,
536 m_hSTOESProjectionMatrixInverted, m_hSTOESTexSamplerInverted,
537 m_hSTOESPositionInverted, m_hSTOESAlphaInverted,
538 m_hSTOESContrastInverted);
541 setBlendingState(forceBlending || opacity < 1.0);
542 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
544 GLUtils::checkGlError("drawLayerQuad");
547 void ShaderProgram::drawVideoLayerQuad(const TransformationMatrix& drawMatrix,
548 float* textureMatrix, SkRect& geometry,
551 // switch to our custom yuv video rendering program
552 glUseProgram(m_videoProgram);
554 TransformationMatrix modifiedDrawMatrix = drawMatrix;
555 modifiedDrawMatrix.translate(geometry.fLeft, geometry.fTop);
556 modifiedDrawMatrix.scale3d(geometry.width(), geometry.height(), 1);
557 TransformationMatrix renderMatrix = m_projectionMatrix * modifiedDrawMatrix;
559 GLfloat projectionMatrix[16];
560 GLUtils::toGLMatrix(projectionMatrix, renderMatrix);
561 glUniformMatrix4fv(m_hVideoProjectionMatrix, 1, GL_FALSE, projectionMatrix);
562 glUniformMatrix4fv(m_hVideoTextureMatrix, 1, GL_FALSE, textureMatrix);
564 glActiveTexture(GL_TEXTURE0);
565 glUniform1i(m_hVideoTexSampler, 0);
566 glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureId);
568 glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]);
569 glEnableVertexAttribArray(m_hVideoPosition);
570 glVertexAttribPointer(m_hVideoPosition, 2, GL_FLOAT, GL_FALSE, 0, 0);
572 setBlendingState(false);
573 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
576 } // namespace WebCore
578 #endif // USE(ACCELERATED_COMPOSITING)