• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #define LOG_TAG "ShaderProgram"
27 #define LOG_NDEBUG 1
28 
29 #include "config.h"
30 #include "ShaderProgram.h"
31 
32 #if USE(ACCELERATED_COMPOSITING)
33 
34 #include "AndroidLog.h"
35 #include "DrawQuadData.h"
36 #include "FloatPoint3D.h"
37 #include "GLUtils.h"
38 #include "TilesManager.h"
39 
40 #include <GLES2/gl2.h>
41 #include <GLES2/gl2ext.h>
42 
43 #define EPSILON 0.00001f
44 
45 namespace WebCore {
46 
47 // fillPortion.xy = starting UV coordinates.
48 // fillPortion.zw = UV coordinates width and height.
49 static const char gVertexShader[] =
50     "attribute vec4 vPosition;\n"
51     "uniform mat4 projectionMatrix;\n"
52     "uniform vec4 fillPortion;\n"
53     "varying vec2 v_texCoord;\n"
54     "void main() {\n"
55     "  gl_Position = projectionMatrix * vPosition;\n"
56     "  v_texCoord = vPosition.xy * fillPortion.zw + fillPortion.xy;\n"
57     "}\n";
58 
59 static const char gRepeatTexFragmentShader[] =
60     "precision mediump float;\n"
61     "varying vec2 v_texCoord; \n"
62     "uniform float alpha; \n"
63     "uniform sampler2D s_texture; \n"
64     "uniform vec2 repeatScale;\n"
65     "void main() {\n"
66     "  vec2 repeatedTexCoord; "
67     "  repeatedTexCoord.x = v_texCoord.x - floor(v_texCoord.x); "
68     "  repeatedTexCoord.y = v_texCoord.y - floor(v_texCoord.y); "
69     "  repeatedTexCoord.x = repeatedTexCoord.x * repeatScale.x; "
70     "  repeatedTexCoord.y = repeatedTexCoord.y * repeatScale.y; "
71     "  gl_FragColor = texture2D(s_texture, repeatedTexCoord); \n"
72     "  gl_FragColor *= alpha; "
73     "}\n";
74 
75 static const char gRepeatTexFragmentShaderInverted[] =
76     "precision mediump float;\n"
77     "varying vec2 v_texCoord; \n"
78     "uniform float alpha; \n"
79     "uniform float contrast; \n"
80     "uniform sampler2D s_texture; \n"
81     "uniform vec2 repeatScale;\n"
82     "void main() {\n"
83     "  vec2 repeatedTexCoord; "
84     "  repeatedTexCoord.x = v_texCoord.x - floor(v_texCoord.x); "
85     "  repeatedTexCoord.y = v_texCoord.y - floor(v_texCoord.y); "
86     "  repeatedTexCoord.x = repeatedTexCoord.x * repeatScale.x; "
87     "  repeatedTexCoord.y = repeatedTexCoord.y * repeatScale.y; "
88     "  vec4 pixel = texture2D(s_texture, repeatedTexCoord); \n"
89     "  float a = pixel.a; \n"
90     "  float color = a - (0.2989 * pixel.r + 0.5866 * pixel.g + 0.1145 * pixel.b);\n"
91     "  color = ((color - a/2.0) * contrast) + a/2.0; \n"
92     "  pixel.rgb = vec3(color, color, color); \n "
93     "  gl_FragColor = pixel; \n"
94     "  gl_FragColor *= alpha; "
95     "}\n";
96 
97 static const char gFragmentShader[] =
98     "precision mediump float;\n"
99     "varying vec2 v_texCoord; \n"
100     "uniform float alpha; \n"
101     "uniform sampler2D s_texture; \n"
102     "void main() {\n"
103     "  gl_FragColor = texture2D(s_texture, v_texCoord); \n"
104     "  gl_FragColor *= alpha; "
105     "}\n";
106 
107 // We could pass the pureColor into either Vertex or Frag Shader.
108 // The reason we passed the color into the Vertex Shader is that some driver
109 // might create redundant copy when uniforms in fragment shader changed.
110 static const char gPureColorVertexShader[] =
111     "attribute vec4 vPosition;\n"
112     "uniform mat4 projectionMatrix;\n"
113     "uniform vec4 inputColor;\n"
114     "varying vec4 v_color;\n"
115     "void main() {\n"
116     "  gl_Position = projectionMatrix * vPosition;\n"
117     "  v_color = inputColor;\n"
118     "}\n";
119 
120 static const char gPureColorFragmentShader[] =
121     "precision mediump float;\n"
122     "varying vec4 v_color;\n"
123     "void main() {\n"
124     "  gl_FragColor = v_color;\n"
125     "}\n";
126 
127 static const char gFragmentShaderInverted[] =
128     "precision mediump float;\n"
129     "varying vec2 v_texCoord; \n"
130     "uniform float alpha; \n"
131     "uniform float contrast; \n"
132     "uniform sampler2D s_texture; \n"
133     "void main() {\n"
134     "  vec4 pixel = texture2D(s_texture, v_texCoord); \n"
135     "  float a = pixel.a; \n"
136     "  float color = a - (0.2989 * pixel.r + 0.5866 * pixel.g + 0.1145 * pixel.b);\n"
137     "  color = ((color - a/2.0) * contrast) + a/2.0; \n"
138     "  pixel.rgb = vec3(color, color, color); \n "
139     "  gl_FragColor = pixel; \n"
140     "  gl_FragColor *= alpha; \n"
141     "}\n";
142 
143 static const char gVideoVertexShader[] =
144     "attribute vec4 vPosition;\n"
145     "uniform mat4 textureMatrix;\n"
146     "uniform mat4 projectionMatrix;\n"
147     "varying vec2 v_texCoord;\n"
148     "void main() {\n"
149     "  gl_Position = projectionMatrix * vPosition;\n"
150     "  v_texCoord = vec2(textureMatrix * vec4(vPosition.x, 1.0 - vPosition.y, 0.0, 1.0));\n"
151     "}\n";
152 
153 static const char gVideoFragmentShader[] =
154     "#extension GL_OES_EGL_image_external : require\n"
155     "precision mediump float;\n"
156     "uniform samplerExternalOES s_yuvTexture;\n"
157     "varying vec2 v_texCoord;\n"
158     "void main() {\n"
159     "  gl_FragColor = texture2D(s_yuvTexture, v_texCoord);\n"
160     "}\n";
161 
162 static const char gSurfaceTextureOESFragmentShader[] =
163     "#extension GL_OES_EGL_image_external : require\n"
164     "precision mediump float;\n"
165     "varying vec2 v_texCoord; \n"
166     "uniform float alpha; \n"
167     "uniform samplerExternalOES s_texture; \n"
168     "void main() {\n"
169     "  gl_FragColor = texture2D(s_texture, v_texCoord); \n"
170     "  gl_FragColor *= alpha; "
171     "}\n";
172 
173 static const char gSurfaceTextureOESFragmentShaderInverted[] =
174     "#extension GL_OES_EGL_image_external : require\n"
175     "precision mediump float;\n"
176     "varying vec2 v_texCoord; \n"
177     "uniform float alpha; \n"
178     "uniform float contrast; \n"
179     "uniform samplerExternalOES s_texture; \n"
180     "void main() {\n"
181     "  vec4 pixel = texture2D(s_texture, v_texCoord); \n"
182     "  float a = pixel.a; \n"
183     "  float color = a - (0.2989 * pixel.r + 0.5866 * pixel.g + 0.1145 * pixel.b);\n"
184     "  color = ((color - a/2.0) * contrast) + a/2.0; \n"
185     "  pixel.rgb = vec3(color, color, color); \n "
186     "  gl_FragColor = pixel; \n"
187     "  gl_FragColor *= alpha; \n"
188     "}\n";
189 
loadShader(GLenum shaderType,const char * pSource)190 GLuint ShaderProgram::loadShader(GLenum shaderType, const char* pSource)
191 {
192     GLuint shader = glCreateShader(shaderType);
193     if (shader) {
194         glShaderSource(shader, 1, &pSource, 0);
195         glCompileShader(shader);
196         GLint compiled = 0;
197         glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
198         if (!compiled) {
199             GLint infoLen = 0;
200             glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
201             if (infoLen) {
202                 char* buf = (char*) malloc(infoLen);
203                 if (buf) {
204                 glGetShaderInfoLog(shader, infoLen, 0, buf);
205                 ALOGE("could not compile shader %d:\n%s\n", shaderType, buf);
206                 free(buf);
207             }
208             glDeleteShader(shader);
209             shader = 0;
210             }
211         }
212     }
213     return shader;
214 }
215 
createProgram(const char * pVertexSource,const char * pFragmentSource)216 GLint ShaderProgram::createProgram(const char* pVertexSource, const char* pFragmentSource)
217 {
218     GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
219     if (!vertexShader) {
220         ALOGE("couldn't load the vertex shader!");
221         return -1;
222     }
223 
224     GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
225     if (!pixelShader) {
226         ALOGE("couldn't load the pixel shader!");
227         return -1;
228     }
229 
230     GLuint program = glCreateProgram();
231     if (program) {
232         glAttachShader(program, vertexShader);
233         GLUtils::checkGlError("glAttachShader vertex");
234         glAttachShader(program, pixelShader);
235         GLUtils::checkGlError("glAttachShader pixel");
236         glLinkProgram(program);
237         GLint linkStatus = GL_FALSE;
238         glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
239         if (linkStatus != GL_TRUE) {
240             GLint bufLength = 0;
241             glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
242             if (bufLength) {
243                 char* buf = (char*) malloc(bufLength);
244                 if (buf) {
245                     glGetProgramInfoLog(program, bufLength, 0, buf);
246                     ALOGE("could not link program:\n%s\n", buf);
247                     free(buf);
248                 }
249             }
250             glDeleteProgram(program);
251             program = -1;
252         }
253     }
254 
255     ShaderResource newResource(program, vertexShader, pixelShader);
256     m_resources.append(newResource);
257     return program;
258 }
259 
ShaderProgram()260 ShaderProgram::ShaderProgram()
261     : m_blendingEnabled(false)
262     , m_contrast(1)
263     , m_alphaLayer(false)
264     , m_currentScale(1.0f)
265     , m_needsInit(true)
266 {
267 }
268 
cleanupGLResources()269 void ShaderProgram::cleanupGLResources()
270 {
271     for (unsigned int i = 0; i < m_resources.size(); i++) {
272         glDetachShader(m_resources[i].program, m_resources[i].vertexShader);
273         glDetachShader(m_resources[i].program, m_resources[i].fragmentShader);
274         glDeleteShader(m_resources[i].vertexShader);
275         glDeleteShader(m_resources[i].fragmentShader);
276         glDeleteProgram(m_resources[i].program);
277     }
278     glDeleteBuffers(1, m_textureBuffer);
279 
280     m_resources.clear();
281     m_needsInit = true;
282     GLUtils::checkGlError("cleanupGLResources");
283 
284     return;
285 }
286 
initGLResources()287 void ShaderProgram::initGLResources()
288 {
289     // To detect whether or not resources for ShaderProgram allocated
290     // successfully, we clean up pre-existing errors here and will check for
291     // new errors at the end of this function.
292     GLUtils::checkGlError("before initGLResources");
293 
294     GLint tex2DProgram = createProgram(gVertexShader, gFragmentShader);
295     GLint pureColorProgram = createProgram(gPureColorVertexShader, gPureColorFragmentShader);
296     GLint tex2DInvProgram = createProgram(gVertexShader, gFragmentShaderInverted);
297     GLint videoProgram = createProgram(gVideoVertexShader, gVideoFragmentShader);
298     GLint texOESProgram =
299         createProgram(gVertexShader, gSurfaceTextureOESFragmentShader);
300     GLint texOESInvProgram =
301         createProgram(gVertexShader, gSurfaceTextureOESFragmentShaderInverted);
302     GLint repeatTexProgram =
303         createProgram(gVertexShader, gRepeatTexFragmentShader);
304     GLint repeatTexInvProgram =
305         createProgram(gVertexShader, gRepeatTexFragmentShaderInverted);
306 
307     if (tex2DProgram == -1
308         || pureColorProgram == -1
309         || tex2DInvProgram == -1
310         || videoProgram == -1
311         || texOESProgram == -1
312         || texOESInvProgram == -1
313         || repeatTexProgram == -1
314         || repeatTexInvProgram == -1) {
315         m_needsInit = true;
316         return;
317     }
318 
319     GLint pureColorPosition = glGetAttribLocation(pureColorProgram, "vPosition");
320     GLint pureColorProjMtx = glGetUniformLocation(pureColorProgram, "projectionMatrix");
321     GLint pureColorValue = glGetUniformLocation(pureColorProgram, "inputColor");
322     m_handleArray[PureColor].init(-1, -1, pureColorPosition, pureColorProgram,
323                                   pureColorProjMtx, pureColorValue, -1, -1, -1, -1);
324 
325     GLint tex2DAlpha = glGetUniformLocation(tex2DProgram, "alpha");
326     GLint tex2DPosition = glGetAttribLocation(tex2DProgram, "vPosition");
327     GLint tex2DProjMtx = glGetUniformLocation(tex2DProgram, "projectionMatrix");
328     GLint tex2DTexSampler = glGetUniformLocation(tex2DProgram, "s_texture");
329     GLint tex2DFillPortion = glGetUniformLocation(tex2DProgram, "fillPortion");
330     m_handleArray[Tex2D].init(tex2DAlpha, -1, tex2DPosition, tex2DProgram,
331                               tex2DProjMtx, -1, tex2DTexSampler, -1, tex2DFillPortion, -1);
332 
333     GLint tex2DInvAlpha = glGetUniformLocation(tex2DInvProgram, "alpha");
334     GLint tex2DInvContrast = glGetUniformLocation(tex2DInvProgram, "contrast");
335     GLint tex2DInvPosition = glGetAttribLocation(tex2DInvProgram, "vPosition");
336     GLint tex2DInvProjMtx = glGetUniformLocation(tex2DInvProgram, "projectionMatrix");
337     GLint tex2DInvTexSampler = glGetUniformLocation(tex2DInvProgram, "s_texture");
338     GLint tex2DInvFillPortion = glGetUniformLocation(tex2DInvProgram, "fillPortion");
339     m_handleArray[Tex2DInv].init(tex2DInvAlpha, tex2DInvContrast,
340                                  tex2DInvPosition, tex2DInvProgram,
341                                  tex2DInvProjMtx, -1,
342                                  tex2DInvTexSampler, -1, tex2DInvFillPortion, -1);
343 
344     GLint repeatTexAlpha = glGetUniformLocation(repeatTexProgram, "alpha");
345     GLint repeatTexPosition = glGetAttribLocation(repeatTexProgram, "vPosition");
346     GLint repeatTexProjMtx = glGetUniformLocation(repeatTexProgram, "projectionMatrix");
347     GLint repeatTexTexSampler = glGetUniformLocation(repeatTexProgram, "s_texture");
348     GLint repeatTexFillPortion = glGetUniformLocation(repeatTexProgram, "fillPortion");
349     GLint repeatTexScale = glGetUniformLocation(repeatTexProgram, "repeatScale");
350     m_handleArray[RepeatTex].init(repeatTexAlpha, -1, repeatTexPosition,
351                                   repeatTexProgram,repeatTexProjMtx, -1,
352                                   repeatTexTexSampler, -1, repeatTexFillPortion,
353                                   repeatTexScale);
354 
355     GLint repeatTexInvAlpha = glGetUniformLocation(repeatTexInvProgram, "alpha");
356     GLint repeatTexInvContrast = glGetUniformLocation(tex2DInvProgram, "contrast");
357     GLint repeatTexInvPosition = glGetAttribLocation(repeatTexInvProgram, "vPosition");
358     GLint repeatTexInvProjMtx = glGetUniformLocation(repeatTexInvProgram, "projectionMatrix");
359     GLint repeatTexInvTexSampler = glGetUniformLocation(repeatTexInvProgram, "s_texture");
360     GLint repeatTexInvFillPortion = glGetUniformLocation(repeatTexInvProgram, "fillPortion");
361     GLint repeatTexInvScale = glGetUniformLocation(repeatTexInvProgram, "repeatScale");
362     m_handleArray[RepeatTexInv].init(repeatTexInvAlpha, repeatTexInvContrast,
363                                      repeatTexInvPosition, repeatTexInvProgram,
364                                      repeatTexInvProjMtx, -1,
365                                      repeatTexInvTexSampler, -1,
366                                      repeatTexInvFillPortion, repeatTexInvScale);
367 
368     GLint texOESAlpha = glGetUniformLocation(texOESProgram, "alpha");
369     GLint texOESPosition = glGetAttribLocation(texOESProgram, "vPosition");
370     GLint texOESProjMtx = glGetUniformLocation(texOESProgram, "projectionMatrix");
371     GLint texOESTexSampler = glGetUniformLocation(texOESProgram, "s_texture");
372     GLint texOESFillPortion = glGetUniformLocation(texOESProgram, "fillPortion");
373     m_handleArray[TexOES].init(texOESAlpha, -1, texOESPosition, texOESProgram,
374                                texOESProjMtx, -1, texOESTexSampler, -1, texOESFillPortion, -1);
375 
376     GLint texOESInvAlpha = glGetUniformLocation(texOESInvProgram, "alpha");
377     GLint texOESInvContrast = glGetUniformLocation(texOESInvProgram, "contrast");
378     GLint texOESInvPosition = glGetAttribLocation(texOESInvProgram, "vPosition");
379     GLint texOESInvProjMtx = glGetUniformLocation(texOESInvProgram, "projectionMatrix");
380     GLint texOESInvTexSampler = glGetUniformLocation(texOESInvProgram, "s_texture");
381     GLint texOESInvFillPortion = glGetUniformLocation(texOESInvProgram, "fillPortion");
382     m_handleArray[TexOESInv].init(texOESInvAlpha, texOESInvContrast,
383                                   texOESInvPosition, texOESInvProgram,
384                                   texOESInvProjMtx, -1,
385                                   texOESInvTexSampler, -1, texOESInvFillPortion, -1);
386 
387     GLint videoPosition = glGetAttribLocation(videoProgram, "vPosition");
388     GLint videoProjMtx = glGetUniformLocation(videoProgram, "projectionMatrix");
389     GLint videoTexSampler = glGetUniformLocation(videoProgram, "s_yuvTexture");
390     GLint videoTexMtx = glGetUniformLocation(videoProgram, "textureMatrix");
391     m_handleArray[Video].init(-1, -1, videoPosition, videoProgram,
392                               videoProjMtx, -1, videoTexSampler,
393                               videoTexMtx, -1, -1);
394 
395     const GLfloat coord[] = {
396         0.0f, 0.0f, // C
397         1.0f, 0.0f, // D
398         0.0f, 1.0f, // A
399         1.0f, 1.0f // B
400     };
401 
402     glGenBuffers(1, m_textureBuffer);
403     glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]);
404     glBufferData(GL_ARRAY_BUFFER, 2 * 4 * sizeof(GLfloat), coord, GL_STATIC_DRAW);
405 
406     TransformationMatrix matrix;
407     // Map x,y from (0,1) to (-1, 1)
408     matrix.scale3d(2, 2, 1);
409     matrix.translate3d(-0.5, -0.5, 0);
410     GLUtils::toGLMatrix(m_transferProjMtx, matrix);
411 
412     m_needsInit = GLUtils::checkGlError("initGLResources");
413     return;
414 }
415 
resetBlending()416 void ShaderProgram::resetBlending()
417 {
418     glDisable(GL_BLEND);
419     glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
420     glBlendEquation(GL_FUNC_ADD);
421     m_blendingEnabled = false;
422 }
423 
setBlendingState(bool enableBlending)424 void ShaderProgram::setBlendingState(bool enableBlending)
425 {
426     if (enableBlending == m_blendingEnabled)
427         return;
428 
429     if (enableBlending)
430         glEnable(GL_BLEND);
431     else
432         glDisable(GL_BLEND);
433 
434     m_blendingEnabled = enableBlending;
435 }
436 
437 /////////////////////////////////////////////////////////////////////////////////////////
438 // Drawing
439 /////////////////////////////////////////////////////////////////////////////////////////
440 
441 // We have multiple coordinates to deal with: first is the screen coordinates,
442 // second is the view coordinates and the last one is content(document) coordinates.
443 // Both screen and view coordinates are in pixels.
444 // All these coordinates start from upper left, but for the purpose of OpenGL
445 // operations, we may need a inverted Y version of such coordinates which
446 // start from lower left.
447 //
448 // invScreenRect - inv screen coordinates starting from lower left.
449 // visibleContentRect - local content(document) coordinates starting from upper left.
450 // screenRect - screen coordinates starting from upper left.
451 // screenClip - screen coordinates starting from upper left.
452 //    ------------------------------------------
453 //    |(origin of screen)                      |
454 //    |screen                                  |
455 //    |   ---------------------------------    |
456 //    |   | (origin of view)              |    |
457 //    |   | webview                       |    |
458 //    |   |        --------               |    |
459 //    |   |        | clip |               |    |
460 //    |   |        |      |               |    |
461 //    |   |        --------               |    |
462 //    |   |                               |    |
463 //    |   |(origin of inv view)           |    |
464 //    |   ---------------------------------    |
465 //    |(origin of inv screen)                  |
466 //    ------------------------------------------
setupDrawing(const IntRect & invScreenRect,const SkRect & visibleContentRect,const IntRect & screenRect,int titleBarHeight,const IntRect & screenClip,float scale)467 void ShaderProgram::setupDrawing(const IntRect& invScreenRect,
468                                  const SkRect& visibleContentRect,
469                                  const IntRect& screenRect, int titleBarHeight,
470                                  const IntRect& screenClip, float scale)
471 {
472     m_screenRect = screenRect;
473     m_titleBarHeight = titleBarHeight;
474 
475     //// viewport ////
476     GLUtils::setOrthographicMatrix(m_visibleContentRectProjectionMatrix,
477                                    visibleContentRect.fLeft,
478                                    visibleContentRect.fTop,
479                                    visibleContentRect.fRight,
480                                    visibleContentRect.fBottom,
481                                    -1000, 1000);
482 
483     ALOGV("set m_clipProjectionMatrix, %d, %d, %d, %d",
484           screenClip.x(), screenClip.y(), screenClip.x() + screenClip.width(),
485           screenClip.y() + screenClip.height());
486 
487     // In order to incorporate the animation delta X and Y, using the clip as
488     // the GL viewport can save all the trouble of re-position from screenRect
489     // to final position.
490     GLUtils::setOrthographicMatrix(m_clipProjectionMatrix, screenClip.x(), screenClip.y(),
491                                    screenClip.x() + screenClip.width(),
492                                    screenClip.y() + screenClip.height(), -1000, 1000);
493 
494     glViewport(screenClip.x(), m_targetHeight - screenClip.y() - screenClip.height() ,
495                screenClip.width(), screenClip.height());
496 
497     m_visibleContentRect = visibleContentRect;
498     m_currentScale = scale;
499 
500 
501     //// viewRect ////
502     m_invScreenRect = invScreenRect;
503 
504     // The following matrices transform content coordinates into view coordinates
505     // and inv view coordinates.
506     // Note that GLUtils::setOrthographicMatrix is inverting the Y.
507     TransformationMatrix viewTranslate;
508     viewTranslate.translate(1.0, 1.0);
509 
510     TransformationMatrix viewScale;
511     viewScale.scale3d(m_invScreenRect.width() * 0.5f, m_invScreenRect.height() * 0.5f, 1);
512 
513     m_contentToInvViewMatrix = viewScale * viewTranslate * m_visibleContentRectProjectionMatrix;
514 
515     viewTranslate.scale3d(1, -1, 1);
516     m_contentToViewMatrix = viewScale * viewTranslate * m_visibleContentRectProjectionMatrix;
517 
518     IntRect invViewRect(0, 0, m_screenRect.width(), m_screenRect.height());
519     m_contentViewport = m_contentToInvViewMatrix.inverse().mapRect(invViewRect);
520 
521 
522     //// clipping ////
523     IntRect viewClip = screenClip;
524 
525     // The incoming screenClip is in screen coordinates, we first
526     // translate it into view coordinates.
527     // Then we convert it into inverted view coordinates.
528     // Therefore, in the clip() function, we need to convert things back from
529     // inverted view coordinates to inverted screen coordinates which is used by GL.
530     viewClip.setX(screenClip.x() - m_screenRect.x());
531     viewClip.setY(screenClip.y() - m_screenRect.y() - m_titleBarHeight);
532     FloatRect invViewClip = convertViewCoordToInvViewCoord(viewClip);
533     m_invViewClip.setLocation(IntPoint(invViewClip.x(), invViewClip.y()));
534     // use ceilf to handle view -> doc -> view coord rounding errors
535     m_invViewClip.setSize(IntSize(ceilf(invViewClip.width()), ceilf(invViewClip.height())));
536 
537     resetBlending();
538 
539     // Set up m_clipProjectionMatrix, m_currentScale and m_webViewMatrix before
540     // calling this function.
541     setupSurfaceProjectionMatrix();
542 }
543 
544 // Calculate the right color value sent into the shader considering the (0,1)
545 // clamp and alpha blending.
shaderColor(Color pureColor,float opacity)546 Color ShaderProgram::shaderColor(Color pureColor, float opacity)
547 {
548     float r = pureColor.red() / 255.0;
549     float g = pureColor.green() / 255.0;
550     float b = pureColor.blue() / 255.0;
551     float a = pureColor.alpha() / 255.0;
552 
553     if (TilesManager::instance()->invertedScreen()) {
554         float intensity = a - (0.2989 * r + 0.5866 * g + 0.1145 * b);
555         intensity = ((intensity - a / 2.0) * m_contrast) + a / 2.0;
556         intensity *= opacity;
557         return Color(intensity, intensity, intensity, a * opacity);
558     }
559     return Color(r * opacity, g * opacity, b * opacity, a * opacity);
560 }
561 
562 // For shaders using texture, it is easy to get the type from the textureTarget.
getTextureShaderType(GLenum textureTarget,bool hasRepeatScale)563 ShaderType ShaderProgram::getTextureShaderType(GLenum textureTarget,
564                                                bool hasRepeatScale)
565 {
566     ShaderType type = UndefinedShader;
567     if (textureTarget == GL_TEXTURE_2D) {
568         if (!TilesManager::instance()->invertedScreen())
569             type = hasRepeatScale ?  RepeatTex : Tex2D;
570         else {
571             // With the new GPU texture upload path, we do not use an FBO
572             // to blit the texture we receive from the TexturesGenerator thread.
573             // To implement inverted rendering, we thus have to do the rendering
574             // live, by using a different shader.
575             type = hasRepeatScale ?  RepeatTexInv : Tex2DInv;
576         }
577     } else if (textureTarget == GL_TEXTURE_EXTERNAL_OES) {
578         if (!TilesManager::instance()->invertedScreen())
579             type = TexOES;
580         else
581             type = TexOESInv;
582     }
583     return type;
584 }
585 
586 // This function transform a clip rect extracted from the current layer
587 // into a clip rect in InvView coordinates -- used by the clipping rects
rectInInvViewCoord(const TransformationMatrix & drawMatrix,const IntSize & size)588 FloatRect ShaderProgram::rectInInvViewCoord(const TransformationMatrix& drawMatrix, const IntSize& size)
589 {
590     FloatRect srect(0, 0, size.width(), size.height());
591     TransformationMatrix renderMatrix = m_contentToInvViewMatrix * drawMatrix;
592     return renderMatrix.mapRect(srect);
593 }
594 
595 // used by the partial screen invals
rectInViewCoord(const TransformationMatrix & drawMatrix,const IntSize & size)596 FloatRect ShaderProgram::rectInViewCoord(const TransformationMatrix& drawMatrix, const IntSize& size)
597 {
598     FloatRect srect(0, 0, size.width(), size.height());
599     TransformationMatrix renderMatrix = m_contentToViewMatrix * drawMatrix;
600     return renderMatrix.mapRect(srect);
601 }
602 
rectInViewCoord(const FloatRect & rect)603 FloatRect ShaderProgram::rectInViewCoord(const FloatRect& rect)
604 {
605     return m_contentToViewMatrix.mapRect(rect);
606 }
607 
rectInInvViewCoord(const FloatRect & rect)608 FloatRect ShaderProgram::rectInInvViewCoord(const FloatRect& rect)
609 {
610     return m_contentToInvViewMatrix.mapRect(rect);
611 }
612 
convertInvViewCoordToContentCoord(const FloatRect & rect)613 FloatRect ShaderProgram::convertInvViewCoordToContentCoord(const FloatRect& rect)
614 {
615     return m_contentToInvViewMatrix.inverse().mapRect(rect);
616 }
617 
convertViewCoordToInvViewCoord(const FloatRect & rect)618 FloatRect ShaderProgram::convertViewCoordToInvViewCoord(const FloatRect& rect)
619 {
620     FloatRect visibleContentRect = m_contentToViewMatrix.inverse().mapRect(rect);
621     return rectInInvViewCoord(visibleContentRect);
622 }
623 
convertInvViewCoordToViewCoord(const FloatRect & rect)624 FloatRect ShaderProgram::convertInvViewCoordToViewCoord(const FloatRect& rect)
625 {
626     FloatRect visibleContentRect = m_contentToInvViewMatrix.inverse().mapRect(rect);
627     return rectInViewCoord(visibleContentRect);
628 }
629 
630 // clip is in screen coordinates
clip(const FloatRect & clip)631 void ShaderProgram::clip(const FloatRect& clip)
632 {
633     if (clip == m_clipRect)
634         return;
635 
636     ALOGV("--clipping rect %f %f, %f x %f",
637           clip.x(), clip.y(), clip.width(), clip.height());
638 
639     // we should only call glScissor in this function, so that we can easily
640     // track the current clipping rect.
641 
642     IntRect screenClip(clip.x(),
643                        clip.y(),
644                        clip.width(), clip.height());
645 
646     if (!m_invViewClip.isEmpty())
647         screenClip.intersect(m_invViewClip);
648 
649     // The previous intersection calculation is using local screen coordinates.
650     // Now we need to convert things from local screen coordinates to global
651     // screen coordinates and pass to the GL functions.
652     screenClip.setX(screenClip.x() + m_invScreenRect.x());
653     screenClip.setY(screenClip.y() + m_invScreenRect.y());
654     if (screenClip.x() < 0) {
655         int w = screenClip.width();
656         w += screenClip.x();
657         screenClip.setX(0);
658         screenClip.setWidth(w);
659     }
660     if (screenClip.y() < 0) {
661         int h = screenClip.height();
662         h += screenClip.y();
663         screenClip.setY(0);
664         screenClip.setHeight(h);
665     }
666 
667     glScissor(screenClip.x(), screenClip.y(), screenClip.width(), screenClip.height());
668 
669     m_clipRect = clip;
670 }
671 
clippedRectWithVisibleContentRect(const IntRect & rect,int margin)672 IntRect ShaderProgram::clippedRectWithVisibleContentRect(const IntRect& rect, int margin)
673 {
674     IntRect viewport(m_visibleContentRect.fLeft - margin, m_visibleContentRect.fTop - margin,
675                      m_visibleContentRect.width() + margin,
676                      m_visibleContentRect.height() + margin);
677     viewport.intersect(rect);
678     return viewport;
679 }
680 
zValue(const TransformationMatrix & drawMatrix,float w,float h)681 float ShaderProgram::zValue(const TransformationMatrix& drawMatrix, float w, float h)
682 {
683     TransformationMatrix modifiedDrawMatrix = drawMatrix;
684     modifiedDrawMatrix.scale3d(w, h, 1);
685     TransformationMatrix renderMatrix =
686         m_visibleContentRectProjectionMatrix * modifiedDrawMatrix;
687     FloatPoint3D point(0.5, 0.5, 0.0);
688     FloatPoint3D result = renderMatrix.mapPoint(point);
689     return result.z();
690 }
691 
drawQuadInternal(ShaderType type,const GLfloat * matrix,int textureId,float opacity,GLenum textureTarget,GLenum filter,const Color & pureColor,const FloatRect & fillPortion,const FloatSize & repeatScale)692 void ShaderProgram::drawQuadInternal(ShaderType type, const GLfloat* matrix,
693                                      int textureId, float opacity,
694                                      GLenum textureTarget, GLenum filter,
695                                      const Color& pureColor, const FloatRect& fillPortion,
696                                      const FloatSize& repeatScale)
697 {
698     glUseProgram(m_handleArray[type].programHandle);
699     glUniformMatrix4fv(m_handleArray[type].projMtxHandle, 1, GL_FALSE, matrix);
700 
701     if (type != PureColor) {
702         glActiveTexture(GL_TEXTURE0);
703         glUniform1i(m_handleArray[type].texSamplerHandle, 0);
704         glBindTexture(textureTarget, textureId);
705         glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, filter);
706         glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, filter);
707         glUniform1f(m_handleArray[type].alphaHandle, opacity);
708 
709         GLint contrastHandle = m_handleArray[type].contrastHandle;
710         if (contrastHandle != -1)
711             glUniform1f(contrastHandle, m_contrast);
712 
713         glUniform4f(m_handleArray[type].fillPortionHandle, fillPortion.x(), fillPortion.y(),
714                     fillPortion.width(), fillPortion.height());
715 
716         // Only when we have repeat scale, this handle can be >= 0;
717         if (m_handleArray[type].scaleHandle != -1) {
718             glUniform2f(m_handleArray[type].scaleHandle,
719                         repeatScale.width(), repeatScale.height());
720         }
721     } else {
722         glUniform4f(m_handleArray[type].pureColorHandle,
723                     pureColor.red() / 255.0, pureColor.green() / 255.0,
724                     pureColor.blue() / 255.0, pureColor.alpha() / 255.0);
725     }
726 
727     GLint positionHandle = m_handleArray[type].positionHandle;
728     glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]);
729     glEnableVertexAttribArray(positionHandle);
730     glVertexAttribPointer(positionHandle, 2, GL_FLOAT, GL_FALSE, 0, 0);
731 
732     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
733 }
734 
735 // Put the common matrix computation at higher level to avoid redundancy.
setupSurfaceProjectionMatrix()736 void ShaderProgram::setupSurfaceProjectionMatrix()
737 {
738     TransformationMatrix scaleMatrix;
739     scaleMatrix.scale3d(m_currentScale, m_currentScale, 1);
740     m_surfaceProjectionMatrix = m_clipProjectionMatrix * m_webViewMatrix * scaleMatrix;
741 }
742 
743 // Calculate the matrix given the geometry.
getTileProjectionMatrix(const DrawQuadData * data)744 GLfloat* ShaderProgram::getTileProjectionMatrix(const DrawQuadData* data)
745 {
746     DrawQuadType type = data->type();
747     if (type == Blit)
748         return m_transferProjMtx;
749 
750     const TransformationMatrix* matrix = data->drawMatrix();
751     const SkRect* geometry = data->geometry();
752     FloatRect fillPortion = data->fillPortion();
753     ALOGV("fillPortion " FLOAT_RECT_FORMAT, FLOAT_RECT_ARGS(fillPortion));
754 
755     // This modifiedDrawMatrix tranform (0,0)(1x1) to the final rect in screen
756     // coordinates, before applying the m_webViewMatrix.
757     // It first scale and translate the vertex array from (0,0)(1x1) to real
758     // tile position and size. Then apply the transform from the layer's.
759     // Finally scale to the currentScale to support zooming.
760     // Note the geometry contains the tile zoom scale, so visually we will see
761     // the tiles scale at a ratio as (m_currentScale/tile's scale).
762     TransformationMatrix modifiedDrawMatrix;
763     if (type == LayerQuad)
764         modifiedDrawMatrix = *matrix;
765     modifiedDrawMatrix.translate(geometry->fLeft + geometry->width() * fillPortion.x(),
766                                  geometry->fTop + geometry->height() * fillPortion.y());
767     modifiedDrawMatrix.scale3d(geometry->width() * fillPortion.width(),
768                                geometry->height() * fillPortion.height(), 1);
769 
770     // Even when we are on a alpha layer or not, we need to respect the
771     // m_webViewMatrix, it may contain the layout offset. Normally it is
772     // identity.
773     TransformationMatrix renderMatrix;
774     renderMatrix = m_surfaceProjectionMatrix * modifiedDrawMatrix;
775 
776 #if DEBUG_MATRIX
777     debugMatrixInfo(m_currentScale, m_clipProjectionMatrix, m_webViewMatrix,
778                     modifiedDrawMatrix, matrix);
779 #endif
780 
781     GLUtils::toGLMatrix(m_tileProjMatrix, renderMatrix);
782     return m_tileProjMatrix;
783 }
784 
drawQuad(const DrawQuadData * data)785 void ShaderProgram::drawQuad(const DrawQuadData* data)
786 {
787     GLfloat* matrix = getTileProjectionMatrix(data);
788 
789     float opacity = data->opacity();
790     bool forceBlending = data->forceBlending();
791     bool enableBlending = forceBlending || opacity < 1.0;
792 
793     ShaderType shaderType = UndefinedShader;
794     int textureId = 0;
795     GLint textureFilter = 0;
796     GLenum textureTarget = 0;
797 
798     Color quadColor = data->quadColor();
799     if (data->pureColor()) {
800         shaderType = PureColor;
801         quadColor = shaderColor(quadColor, opacity);
802         enableBlending = enableBlending || quadColor.hasAlpha();
803         if (!quadColor.alpha() && enableBlending)
804             return;
805     } else {
806         textureId = data->textureId();
807         textureFilter = data->textureFilter();
808         textureTarget = data->textureTarget();
809         shaderType = getTextureShaderType(textureTarget, data->hasRepeatScale());
810     }
811     setBlendingState(enableBlending);
812     drawQuadInternal(shaderType, matrix, textureId, opacity,
813                      textureTarget, textureFilter, quadColor, data->fillPortion(),
814                      data->repeatScale());
815 }
816 
drawVideoLayerQuad(const TransformationMatrix & drawMatrix,float * textureMatrix,SkRect & geometry,int textureId)817 void ShaderProgram::drawVideoLayerQuad(const TransformationMatrix& drawMatrix,
818                                        float* textureMatrix, SkRect& geometry,
819                                        int textureId)
820 {
821     // switch to our custom yuv video rendering program
822     glUseProgram(m_handleArray[Video].programHandle);
823     // TODO: Merge drawVideoLayerQuad into drawQuad.
824     TransformationMatrix modifiedDrawMatrix;
825     modifiedDrawMatrix.scale3d(m_currentScale, m_currentScale, 1);
826     modifiedDrawMatrix.multiply(drawMatrix);
827     modifiedDrawMatrix.translate(geometry.fLeft, geometry.fTop);
828     modifiedDrawMatrix.scale3d(geometry.width(), geometry.height(), 1);
829     TransformationMatrix renderMatrix =
830         m_clipProjectionMatrix * m_webViewMatrix * modifiedDrawMatrix;
831 
832     GLfloat projectionMatrix[16];
833     GLUtils::toGLMatrix(projectionMatrix, renderMatrix);
834     glUniformMatrix4fv(m_handleArray[Video].projMtxHandle, 1, GL_FALSE,
835                        projectionMatrix);
836     glUniformMatrix4fv(m_handleArray[Video].videoMtxHandle, 1, GL_FALSE,
837                        textureMatrix);
838     glActiveTexture(GL_TEXTURE0);
839     glUniform1i(m_handleArray[Video].texSamplerHandle, 0);
840     glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureId);
841 
842     GLint videoPosition = m_handleArray[Video].positionHandle;
843     glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]);
844     glEnableVertexAttribArray(videoPosition);
845     glVertexAttribPointer(videoPosition, 2, GL_FLOAT, GL_FALSE, 0, 0);
846 
847     setBlendingState(false);
848     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
849 }
850 
setGLDrawInfo(const android::uirenderer::DrawGlInfo * info)851 void ShaderProgram::setGLDrawInfo(const android::uirenderer::DrawGlInfo* info)
852 {
853     GLUtils::convertToTransformationMatrix(info->transform, m_webViewMatrix);
854     m_alphaLayer = info->isLayer;
855     m_targetHeight = info->height;
856 }
857 
858 // This function is called per tileGrid to minimize the computation overhead.
859 // The ortho projection and glViewport will map 1:1, so we don't need to
860 // worry about them here. Basically, if the current zoom scale / tile's scale
861 // plus the webview and layer transformation ends up at scale factor 1.0,
862 // then we can use point sampling.
usePointSampling(float tileScale,const TransformationMatrix * layerTransform)863 bool ShaderProgram::usePointSampling(float tileScale,
864                                      const TransformationMatrix* layerTransform)
865 {
866     const float testSize = 1.0;
867     FloatRect rect(0, 0, testSize, testSize);
868     TransformationMatrix matrix;
869     matrix.scale3d(m_currentScale, m_currentScale, 1);
870     if (layerTransform)
871         matrix.multiply(*layerTransform);
872     matrix.scale3d(1.0 / tileScale, 1.0 / tileScale, 1);
873 
874     matrix = m_webViewMatrix * matrix;
875 
876     rect = matrix.mapRect(rect);
877 
878     float deltaWidth = abs(rect.width() - testSize);
879     float deltaHeight = abs(rect.height() - testSize);
880 
881     if (deltaWidth < EPSILON && deltaHeight < EPSILON) {
882         ALOGV("Point sampling : deltaWidth is %f, deltaHeight is %f", deltaWidth, deltaHeight);
883         return true;
884     }
885     return false;
886 }
887 
888 #if DEBUG_MATRIX
debugMatrixTransform(const TransformationMatrix & matrix,const char * matrixName)889 FloatRect ShaderProgram::debugMatrixTransform(const TransformationMatrix& matrix,
890                                               const char* matrixName)
891 {
892     FloatRect rect(0.0, 0.0, 1.0, 1.0);
893     rect = matrix.mapRect(rect);
894     ALOGV("After %s matrix:\n %f, %f rect.width() %f rect.height() %f",
895           matrixName, rect.x(), rect.y(), rect.width(), rect.height());
896     return rect;
897 
898 }
899 
debugMatrixInfo(float currentScale,const TransformationMatrix & clipProjectionMatrix,const TransformationMatrix & webViewMatrix,const TransformationMatrix & modifiedDrawMatrix,const TransformationMatrix * layerMatrix)900 void ShaderProgram::debugMatrixInfo(float currentScale,
901                                     const TransformationMatrix& clipProjectionMatrix,
902                                     const TransformationMatrix& webViewMatrix,
903                                     const TransformationMatrix& modifiedDrawMatrix,
904                                     const TransformationMatrix* layerMatrix)
905 {
906     int viewport[4];
907     glGetIntegerv(GL_VIEWPORT, viewport);
908     ALOGV("viewport %d, %d, %d, %d , currentScale %f",
909           viewport[0], viewport[1], viewport[2], viewport[3], currentScale);
910     IntRect currentGLViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
911 
912     TransformationMatrix scaleMatrix;
913     scaleMatrix.scale3d(currentScale, currentScale, 1.0);
914 
915     if (layerMatrix)
916         debugMatrixTransform(*layerMatrix, "layerMatrix");
917 
918     TransformationMatrix debugMatrix = scaleMatrix * modifiedDrawMatrix;
919     debugMatrixTransform(debugMatrix, "scaleMatrix * modifiedDrawMatrix");
920 
921     debugMatrix = webViewMatrix * debugMatrix;
922     debugMatrixTransform(debugMatrix, "webViewMatrix * scaleMatrix * modifiedDrawMatrix");
923 
924     debugMatrix = clipProjectionMatrix * debugMatrix;
925     FloatRect finalRect =
926         debugMatrixTransform(debugMatrix, "all Matrix");
927     // After projection, we will be in a (-1, 1) range and now we can map it back
928     // to the (x,y) -> (x+width, y+height)
929     ALOGV("final convert to screen coord x, y %f, %f width %f height %f , ",
930           (finalRect.x() + 1) / 2 * currentGLViewport.width() + currentGLViewport.x(),
931           (finalRect.y() + 1) / 2 * currentGLViewport.height() + currentGLViewport.y(),
932           finalRect.width() * currentGLViewport.width() / 2,
933           finalRect.height() * currentGLViewport.height() / 2);
934 }
935 #endif // DEBUG_MATRIX
936 
937 } // namespace WebCore
938 #endif // USE(ACCELERATED_COMPOSITING)
939