OSDN Git Service

Merge "Remove old customized code."
[android-x86/external-webkit.git] / Source / WebCore / platform / graphics / android / ShaderProgram.cpp
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 #include "config.h"
27 #include "ShaderProgram.h"
28
29 #if USE(ACCELERATED_COMPOSITING)
30
31 #include "FloatPoint3D.h"
32 #include "GLUtils.h"
33
34 #include <GLES2/gl2.h>
35 #include <cutils/log.h>
36 #include <wtf/CurrentTime.h>
37 #include <wtf/text/CString.h>
38
39 #undef XLOG
40 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "ShaderProgram", __VA_ARGS__)
41
42 namespace WebCore {
43
44 static const char gVertexShader[] =
45     "attribute vec4 vPosition;\n"
46     "uniform mat4 projectionMatrix;\n"
47     "varying vec2 v_texCoord;\n"
48     "void main() {\n"
49     "  gl_Position = projectionMatrix * vPosition;\n"
50     "  v_texCoord = vec2(vPosition);\n"
51     "}\n";
52
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"
59     "void main() {\n"
60     "  gl_FragColor = texture2D(s_texture, v_texCoord); \n"
61     "  gl_FragColor *= alpha; "
62     "}\n";
63
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"
69     "void main() {\n"
70     "  gl_Position = projectionMatrix * vPosition;\n"
71     "  v_texCoord = vec2(textureMatrix * vec4(vPosition.x, 1.0 - vPosition.y, 0.0, 1.0));\n"
72     "}\n";
73
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"
79     "void main() {\n"
80     "  gl_FragColor = texture2D(s_yuvTexture, v_texCoord);\n"
81     "}\n";
82
83 GLuint ShaderProgram::loadShader(GLenum shaderType, const char* pSource)
84 {
85     GLuint shader = glCreateShader(shaderType);
86     if (shader) {
87         glShaderSource(shader, 1, &pSource, 0);
88         glCompileShader(shader);
89         GLint compiled = 0;
90         glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
91         if (!compiled) {
92             GLint infoLen = 0;
93             glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
94             if (infoLen) {
95                 char* buf = (char*) malloc(infoLen);
96                 if (buf) {
97                 glGetShaderInfoLog(shader, infoLen, 0, buf);
98                 XLOG("could not compile shader %d:\n%s\n", shaderType, buf);
99                 free(buf);
100             }
101             glDeleteShader(shader);
102             shader = 0;
103             }
104         }
105     }
106     return shader;
107 }
108
109 GLuint ShaderProgram::createProgram(const char* pVertexSource, const char* pFragmentSource)
110 {
111     GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
112     if (!vertexShader) {
113         XLOG("couldn't load the vertex shader!");
114         return -1;
115     }
116
117     GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
118     if (!pixelShader) {
119         XLOG("couldn't load the pixel shader!");
120         return -1;
121     }
122
123     GLuint program = glCreateProgram();
124     if (program) {
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) {
133             GLint bufLength = 0;
134             glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
135             if (bufLength) {
136                 char* buf = (char*) malloc(bufLength);
137                 if (buf) {
138                     glGetProgramInfoLog(program, bufLength, 0, buf);
139                     XLOG("could not link program:\n%s\n", buf);
140                     free(buf);
141                 }
142             }
143             glDeleteProgram(program);
144             program = -1;
145         }
146     }
147     return program;
148 }
149
150 ShaderProgram::ShaderProgram()
151     : m_blendingEnabled(false)
152 {
153     init();
154 }
155
156 void ShaderProgram::init()
157 {
158     m_program = createProgram(gVertexShader, gFragmentShader);
159     m_videoProgram = createProgram(gVideoVertexShader, gVideoFragmentShader);
160     if (m_program == -1 || m_videoProgram == -1)
161         return;
162
163     m_hProjectionMatrix = glGetUniformLocation(m_program, "projectionMatrix");
164     m_hAlpha = glGetUniformLocation(m_program, "alpha");
165     m_hTexSampler = glGetUniformLocation(m_program, "s_texture");
166
167     m_hPosition = glGetAttribLocation(m_program, "vPosition");
168
169     m_hVideoProjectionMatrix = glGetUniformLocation(m_videoProgram, "projectionMatrix");
170     m_hVideoTextureMatrix = glGetUniformLocation(m_videoProgram, "textureMatrix");
171     m_hVideoTexSampler = glGetUniformLocation(m_videoProgram, "s_yuvTexture");
172
173     m_hVideoPosition = glGetAttribLocation(m_program, "vPosition");
174
175     const GLfloat coord[] = {
176         0.0f, 0.0f, // C
177         1.0f, 0.0f, // D
178         0.0f, 1.0f, // A
179         1.0f, 1.0f // B
180     };
181
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);
185 }
186
187 void ShaderProgram::resetBlending()
188 {
189     glDisable(GL_BLEND);
190     glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
191     glBlendEquation(GL_FUNC_ADD);
192     m_blendingEnabled = false;
193 }
194
195 void ShaderProgram::setBlendingState(bool enableBlending)
196 {
197     if (enableBlending == m_blendingEnabled)
198         return;
199
200     if (enableBlending)
201         glEnable(GL_BLEND);
202     else
203         glDisable(GL_BLEND);
204
205     m_blendingEnabled = enableBlending;
206 }
207
208 /////////////////////////////////////////////////////////////////////////////////////////
209 // Drawing
210 /////////////////////////////////////////////////////////////////////////////////////////
211
212 void ShaderProgram::setViewport(SkRect& viewport)
213 {
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;
219 }
220
221 void ShaderProgram::setProjectionMatrix(SkRect& geometry)
222 {
223     TransformationMatrix translate;
224     translate.translate3d(geometry.fLeft, geometry.fTop, 0.0);
225     TransformationMatrix scale;
226     scale.scale3d(geometry.width(), geometry.height(), 1.0);
227
228     TransformationMatrix total = m_projectionMatrix * translate * scale;
229
230     GLfloat projectionMatrix[16];
231     GLUtils::toGLMatrix(projectionMatrix, total);
232     glUniformMatrix4fv(m_hProjectionMatrix, 1, GL_FALSE, projectionMatrix);
233 }
234
235 void ShaderProgram::drawQuad(SkRect& geometry, int textureId, float opacity)
236 {
237     setProjectionMatrix(geometry);
238
239     glActiveTexture(GL_TEXTURE0);
240     glBindTexture(GL_TEXTURE_2D, textureId);
241
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);
246
247     setBlendingState(opacity < 1.0);
248     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
249
250     GLUtils::checkGlError("drawQuad");
251 }
252
253 void ShaderProgram::setViewRect(const IntRect& viewRect)
254 {
255     m_viewRect = viewRect;
256
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);
262
263     TransformationMatrix scale;
264     scale.scale3d(m_viewRect.width() * 0.5f, m_viewRect.height() * 0.5f, 1);
265
266     m_documentToScreenMatrix = scale * translate * m_projectionMatrix;
267
268     translate.scale3d(1, -1, 1);
269     m_documentToInvScreenMatrix = scale * translate * m_projectionMatrix;
270 }
271
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)
275 {
276     FloatRect srect(0, 0, size.width(), size.height());
277     TransformationMatrix renderMatrix = m_documentToScreenMatrix * drawMatrix;
278     return renderMatrix.mapRect(srect);
279 }
280
281 // used by the partial screen invals
282 FloatRect ShaderProgram::rectInInvScreenCoord(const TransformationMatrix& drawMatrix, const IntSize& size)
283 {
284     FloatRect srect(0, 0, size.width(), size.height());
285     TransformationMatrix renderMatrix = m_documentToInvScreenMatrix * drawMatrix;
286     return renderMatrix.mapRect(srect);
287 }
288
289 FloatRect ShaderProgram::rectInInvScreenCoord(const FloatRect& rect)
290 {
291     return m_documentToInvScreenMatrix.mapRect(rect);
292 }
293
294 FloatRect ShaderProgram::rectInScreenCoord(const FloatRect& rect)
295 {
296     return m_documentToScreenMatrix.mapRect(rect);
297 }
298
299 FloatRect ShaderProgram::convertInvScreenCoordToScreenCoord(const FloatRect& rect)
300 {
301     FloatRect documentRect = m_documentToInvScreenMatrix.inverse().mapRect(rect);
302     return rectInScreenCoord(documentRect);
303 }
304
305 FloatRect ShaderProgram::convertScreenCoordToInvScreenCoord(const FloatRect& rect)
306 {
307     FloatRect documentRect = m_documentToScreenMatrix.inverse().mapRect(rect);
308     return rectInInvScreenCoord(documentRect);
309 }
310
311 void ShaderProgram::setScreenClip(const IntRect& clip)
312 {
313     m_screenClip = clip;
314     IntRect mclip = clip;
315
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;
321 }
322
323 // clip is in screen coordinates
324 void ShaderProgram::clip(const FloatRect& clip)
325 {
326     if (clip == m_clipRect)
327         return;
328
329     // we should only call glScissor in this function, so that we can easily
330     // track the current clipping rect.
331
332     IntRect screenClip(clip.x(),
333                        clip.y(),
334                        clip.width(), clip.height());
335
336     if (!m_screenClip.isEmpty())
337         screenClip.intersect(m_screenClip);
338
339     screenClip.setY(screenClip.y() + m_viewRect.y());
340     if (screenClip.x() < 0) {
341         int w = screenClip.width();
342         w += screenClip.x();
343         screenClip.setX(0);
344         screenClip.setWidth(w);
345     }
346     if (screenClip.y() < 0) {
347         int h = screenClip.height();
348         h += screenClip.y();
349         screenClip.setY(0);
350         screenClip.setHeight(h);
351     }
352
353     glScissor(screenClip.x(), screenClip.y(), screenClip.width(), screenClip.height());
354
355     m_clipRect = clip;
356 }
357
358 IntRect ShaderProgram::clippedRectWithViewport(const IntRect& rect, int margin)
359 {
360     IntRect viewport(m_viewport.fLeft - margin, m_viewport.fTop - margin,
361                      m_viewport.width() + margin, m_viewport.height() + margin);
362     viewport.intersect(rect);
363     return viewport;
364 }
365
366 float ShaderProgram::zValue(const TransformationMatrix& drawMatrix, float w, float h)
367 {
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);
373     return result.z();
374 }
375
376 void ShaderProgram::drawLayerQuad(const TransformationMatrix& drawMatrix,
377                                   SkRect& geometry, int textureId, float opacity,
378                                   bool forceBlending)
379 {
380
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;
386
387     GLfloat projectionMatrix[16];
388     GLUtils::toGLMatrix(projectionMatrix, renderMatrix);
389     glUniformMatrix4fv(m_hProjectionMatrix, 1, GL_FALSE, projectionMatrix);
390
391     glActiveTexture(GL_TEXTURE0);
392     glBindTexture(GL_TEXTURE_2D, textureId);
393
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);
398
399     setBlendingState(forceBlending || opacity < 1.0);
400     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
401 }
402
403 void ShaderProgram::drawVideoLayerQuad(const TransformationMatrix& drawMatrix,
404                                        float* textureMatrix, SkRect& geometry,
405                                        int textureId)
406 {
407     // switch to our custom yuv video rendering program
408     glUseProgram(m_videoProgram);
409
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;
414
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);
419
420     glActiveTexture(GL_TEXTURE0);
421     glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureId);
422
423     glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]);
424     glEnableVertexAttribArray(m_hVideoPosition);
425     glVertexAttribPointer(m_hVideoPosition, 2, GL_FLOAT, GL_FALSE, 0, 0);
426
427     setBlendingState(false);
428     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
429
430     // switch back to our normal rendering program
431     glUseProgram(m_program);
432 }
433
434 } // namespace WebCore
435
436 #endif // USE(ACCELERATED_COMPOSITING)