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"
34 #include <GLES2/gl2.h>
35 #include <cutils/log.h>
36 #include <wtf/CurrentTime.h>
37 #include <wtf/text/CString.h>
40 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "ShaderProgram", __VA_ARGS__)
44 static const char gVertexShader[] =
45 "attribute vec4 vPosition;\n"
46 "uniform mat4 projectionMatrix;\n"
47 "varying vec2 v_texCoord;\n"
49 " gl_Position = projectionMatrix * vPosition;\n"
50 " v_texCoord = vec2(vPosition);\n"
53 static const char gFragmentShader[] =
54 "#extension GL_OES_EGL_image_external : require\n"
55 "precision mediump float;\n"
56 "varying vec2 v_texCoord; \n"
57 "uniform float alpha; \n"
58 "uniform sampler2D s_texture; \n"
60 " gl_FragColor = texture2D(s_texture, v_texCoord); \n"
61 " gl_FragColor *= alpha; "
64 static const char gVideoVertexShader[] =
65 "attribute vec4 vPosition;\n"
66 "uniform mat4 textureMatrix;\n"
67 "uniform mat4 projectionMatrix;\n"
68 "varying vec2 v_texCoord;\n"
70 " gl_Position = projectionMatrix * vPosition;\n"
71 " v_texCoord = vec2(textureMatrix * vec4(vPosition.x, 1.0 - vPosition.y, 0.0, 1.0));\n"
74 static const char gVideoFragmentShader[] =
75 "#extension GL_OES_EGL_image_external : require\n"
76 "precision mediump float;\n"
77 "uniform samplerExternalOES s_yuvTexture;\n"
78 "varying vec2 v_texCoord;\n"
80 " gl_FragColor = texture2D(s_yuvTexture, v_texCoord);\n"
83 GLuint ShaderProgram::loadShader(GLenum shaderType, const char* pSource)
85 GLuint shader = glCreateShader(shaderType);
87 glShaderSource(shader, 1, &pSource, 0);
88 glCompileShader(shader);
90 glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
93 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
95 char* buf = (char*) malloc(infoLen);
97 glGetShaderInfoLog(shader, infoLen, 0, buf);
98 XLOG("could not compile shader %d:\n%s\n", shaderType, buf);
101 glDeleteShader(shader);
109 GLuint ShaderProgram::createProgram(const char* pVertexSource, const char* pFragmentSource)
111 GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
113 XLOG("couldn't load the vertex shader!");
117 GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
119 XLOG("couldn't load the pixel shader!");
123 GLuint program = glCreateProgram();
125 glAttachShader(program, vertexShader);
126 GLUtils::checkGlError("glAttachShader vertex");
127 glAttachShader(program, pixelShader);
128 GLUtils::checkGlError("glAttachShader pixel");
129 glLinkProgram(program);
130 GLint linkStatus = GL_FALSE;
131 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
132 if (linkStatus != GL_TRUE) {
134 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
136 char* buf = (char*) malloc(bufLength);
138 glGetProgramInfoLog(program, bufLength, 0, buf);
139 XLOG("could not link program:\n%s\n", buf);
143 glDeleteProgram(program);
150 ShaderProgram::ShaderProgram()
151 : m_blendingEnabled(false)
156 void ShaderProgram::init()
158 m_program = createProgram(gVertexShader, gFragmentShader);
159 m_videoProgram = createProgram(gVideoVertexShader, gVideoFragmentShader);
160 if (m_program == -1 || m_videoProgram == -1)
163 m_hProjectionMatrix = glGetUniformLocation(m_program, "projectionMatrix");
164 m_hAlpha = glGetUniformLocation(m_program, "alpha");
165 m_hTexSampler = glGetUniformLocation(m_program, "s_texture");
167 m_hPosition = glGetAttribLocation(m_program, "vPosition");
169 m_hVideoProjectionMatrix = glGetUniformLocation(m_videoProgram, "projectionMatrix");
170 m_hVideoTextureMatrix = glGetUniformLocation(m_videoProgram, "textureMatrix");
171 m_hVideoTexSampler = glGetUniformLocation(m_videoProgram, "s_yuvTexture");
173 m_hVideoPosition = glGetAttribLocation(m_program, "vPosition");
175 const GLfloat coord[] = {
182 glGenBuffers(1, m_textureBuffer);
183 glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]);
184 glBufferData(GL_ARRAY_BUFFER, 2 * 4 * sizeof(GLfloat), coord, GL_STATIC_DRAW);
187 void ShaderProgram::resetBlending()
190 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
191 glBlendEquation(GL_FUNC_ADD);
192 m_blendingEnabled = false;
195 void ShaderProgram::setBlendingState(bool enableBlending)
197 if (enableBlending == m_blendingEnabled)
205 m_blendingEnabled = enableBlending;
208 /////////////////////////////////////////////////////////////////////////////////////////
210 /////////////////////////////////////////////////////////////////////////////////////////
212 void ShaderProgram::setViewport(SkRect& viewport)
214 TransformationMatrix ortho;
215 GLUtils::setOrthographicMatrix(ortho, viewport.fLeft, viewport.fTop,
216 viewport.fRight, viewport.fBottom, -1000, 1000);
217 m_projectionMatrix = ortho;
218 m_viewport = viewport;
221 void ShaderProgram::setProjectionMatrix(SkRect& geometry)
223 TransformationMatrix translate;
224 translate.translate3d(geometry.fLeft, geometry.fTop, 0.0);
225 TransformationMatrix scale;
226 scale.scale3d(geometry.width(), geometry.height(), 1.0);
228 TransformationMatrix total = m_projectionMatrix * translate * scale;
230 GLfloat projectionMatrix[16];
231 GLUtils::toGLMatrix(projectionMatrix, total);
232 glUniformMatrix4fv(m_hProjectionMatrix, 1, GL_FALSE, projectionMatrix);
235 void ShaderProgram::drawQuad(SkRect& geometry, int textureId, float opacity)
237 setProjectionMatrix(geometry);
239 glActiveTexture(GL_TEXTURE0);
240 glBindTexture(GL_TEXTURE_2D, textureId);
242 glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]);
243 glEnableVertexAttribArray(m_hPosition);
244 glVertexAttribPointer(m_hPosition, 2, GL_FLOAT, GL_FALSE, 0, 0);
245 glUniform1f(alpha(), opacity);
247 setBlendingState(opacity < 1.0);
248 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
250 GLUtils::checkGlError("drawQuad");
253 void ShaderProgram::setViewRect(const IntRect& viewRect)
255 m_viewRect = viewRect;
257 // We do clipping using glScissor, which needs to take
258 // coordinates in screen space. The following matrix transform
259 // content coordinates in screen coordinates.
260 TransformationMatrix translate;
261 translate.translate(1.0, 1.0);
263 TransformationMatrix scale;
264 scale.scale3d(m_viewRect.width() * 0.5f, m_viewRect.height() * 0.5f, 1);
266 m_documentToScreenMatrix = scale * translate * m_projectionMatrix;
268 translate.scale3d(1, -1, 1);
269 m_documentToInvScreenMatrix = scale * translate * m_projectionMatrix;
272 // This function transform a clip rect extracted from the current layer
273 // into a clip rect in screen coordinates -- used by the clipping rects
274 FloatRect ShaderProgram::rectInScreenCoord(const TransformationMatrix& drawMatrix, const IntSize& size)
276 FloatRect srect(0, 0, size.width(), size.height());
277 TransformationMatrix renderMatrix = m_documentToScreenMatrix * drawMatrix;
278 return renderMatrix.mapRect(srect);
281 // used by the partial screen invals
282 FloatRect ShaderProgram::rectInInvScreenCoord(const TransformationMatrix& drawMatrix, const IntSize& size)
284 FloatRect srect(0, 0, size.width(), size.height());
285 TransformationMatrix renderMatrix = m_documentToInvScreenMatrix * drawMatrix;
286 return renderMatrix.mapRect(srect);
289 FloatRect ShaderProgram::rectInInvScreenCoord(const FloatRect& rect)
291 return m_documentToInvScreenMatrix.mapRect(rect);
294 FloatRect ShaderProgram::rectInScreenCoord(const FloatRect& rect)
296 return m_documentToScreenMatrix.mapRect(rect);
299 FloatRect ShaderProgram::convertInvScreenCoordToScreenCoord(const FloatRect& rect)
301 FloatRect documentRect = m_documentToInvScreenMatrix.inverse().mapRect(rect);
302 return rectInScreenCoord(documentRect);
305 FloatRect ShaderProgram::convertScreenCoordToInvScreenCoord(const FloatRect& rect)
307 FloatRect documentRect = m_documentToScreenMatrix.inverse().mapRect(rect);
308 return rectInInvScreenCoord(documentRect);
311 void ShaderProgram::setScreenClip(const IntRect& clip)
314 IntRect mclip = clip;
316 // the clip from frameworks is in full screen coordinates
317 mclip.setY(clip.y() - m_webViewRect.y() - m_titleBarHeight);
318 FloatRect tclip = convertInvScreenCoordToScreenCoord(mclip);
319 IntRect screenClip(tclip.x(), tclip.y(), tclip.width(), tclip.height());
320 m_screenClip = screenClip;
323 // clip is in screen coordinates
324 void ShaderProgram::clip(const FloatRect& clip)
326 if (clip == m_clipRect)
329 // we should only call glScissor in this function, so that we can easily
330 // track the current clipping rect.
332 IntRect screenClip(clip.x(),
334 clip.width(), clip.height());
336 if (!m_screenClip.isEmpty())
337 screenClip.intersect(m_screenClip);
339 screenClip.setY(screenClip.y() + m_viewRect.y());
340 if (screenClip.x() < 0) {
341 int w = screenClip.width();
344 screenClip.setWidth(w);
346 if (screenClip.y() < 0) {
347 int h = screenClip.height();
350 screenClip.setHeight(h);
353 glScissor(screenClip.x(), screenClip.y(), screenClip.width(), screenClip.height());
358 IntRect ShaderProgram::clippedRectWithViewport(const IntRect& rect, int margin)
360 IntRect viewport(m_viewport.fLeft - margin, m_viewport.fTop - margin,
361 m_viewport.width() + margin, m_viewport.height() + margin);
362 viewport.intersect(rect);
366 float ShaderProgram::zValue(const TransformationMatrix& drawMatrix, float w, float h)
368 TransformationMatrix modifiedDrawMatrix = drawMatrix;
369 modifiedDrawMatrix.scale3d(w, h, 1);
370 TransformationMatrix renderMatrix = m_projectionMatrix * modifiedDrawMatrix;
371 FloatPoint3D point(0.5, 0.5, 0.0);
372 FloatPoint3D result = renderMatrix.mapPoint(point);
376 void ShaderProgram::drawLayerQuad(const TransformationMatrix& drawMatrix,
377 SkRect& geometry, int textureId, float opacity,
381 TransformationMatrix modifiedDrawMatrix = drawMatrix;
382 // move the drawing depending on where the texture is on the layer
383 modifiedDrawMatrix.translate(geometry.fLeft, geometry.fTop);
384 modifiedDrawMatrix.scale3d(geometry.width(), geometry.height(), 1);
385 TransformationMatrix renderMatrix = m_projectionMatrix * modifiedDrawMatrix;
387 GLfloat projectionMatrix[16];
388 GLUtils::toGLMatrix(projectionMatrix, renderMatrix);
389 glUniformMatrix4fv(m_hProjectionMatrix, 1, GL_FALSE, projectionMatrix);
391 glActiveTexture(GL_TEXTURE0);
392 glBindTexture(GL_TEXTURE_2D, textureId);
394 glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]);
395 glEnableVertexAttribArray(m_hPosition);
396 glVertexAttribPointer(m_hPosition, 2, GL_FLOAT, GL_FALSE, 0, 0);
397 glUniform1f(alpha(), opacity);
399 setBlendingState(forceBlending || opacity < 1.0);
400 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
403 void ShaderProgram::drawVideoLayerQuad(const TransformationMatrix& drawMatrix,
404 float* textureMatrix, SkRect& geometry,
407 // switch to our custom yuv video rendering program
408 glUseProgram(m_videoProgram);
410 TransformationMatrix modifiedDrawMatrix = drawMatrix;
411 modifiedDrawMatrix.translate(geometry.fLeft, geometry.fTop);
412 modifiedDrawMatrix.scale3d(geometry.width(), geometry.height(), 1);
413 TransformationMatrix renderMatrix = m_projectionMatrix * modifiedDrawMatrix;
415 GLfloat projectionMatrix[16];
416 GLUtils::toGLMatrix(projectionMatrix, renderMatrix);
417 glUniformMatrix4fv(m_hVideoProjectionMatrix, 1, GL_FALSE, projectionMatrix);
418 glUniformMatrix4fv(m_hVideoTextureMatrix, 1, GL_FALSE, textureMatrix);
420 glActiveTexture(GL_TEXTURE0);
421 glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureId);
423 glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]);
424 glEnableVertexAttribArray(m_hVideoPosition);
425 glVertexAttribPointer(m_hVideoPosition, 2, GL_FLOAT, GL_FALSE, 0, 0);
427 setBlendingState(false);
428 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
430 // switch back to our normal rendering program
431 glUseProgram(m_program);
434 } // namespace WebCore
436 #endif // USE(ACCELERATED_COMPOSITING)