• 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 
initProgram(ShaderType type)260 void ShaderProgram::initProgram(ShaderType type)
261 {
262     // initialize shader's static texSampler and position values
263     glUseProgram(m_handleArray[type].programHandle);
264 
265     if (m_handleArray[type].texSamplerHandle != -1)
266         glUniform1i(m_handleArray[type].texSamplerHandle, 0);
267     glEnableVertexAttribArray(m_handleArray[type].positionHandle);
268 }
269 
ShaderProgram()270 ShaderProgram::ShaderProgram()
271     : m_blendingEnabled(false)
272     , m_contrast(1)
273     , m_alphaLayer(false)
274     , m_currentScale(1.0f)
275     , m_needsInit(true)
276 {
277     // initialize the matrix to calculate z values correctly, since it can be
278     // used for that before setupDrawing is called.
279     GLUtils::setOrthographicMatrix(m_visibleContentRectProjectionMatrix,
280                                    0,0,1,1,
281                                    -1000, 1000);
282 }
283 
cleanupGLResources()284 void ShaderProgram::cleanupGLResources()
285 {
286     for (unsigned int i = 0; i < m_resources.size(); i++) {
287         glDetachShader(m_resources[i].program, m_resources[i].vertexShader);
288         glDetachShader(m_resources[i].program, m_resources[i].fragmentShader);
289         glDeleteShader(m_resources[i].vertexShader);
290         glDeleteShader(m_resources[i].fragmentShader);
291         glDeleteProgram(m_resources[i].program);
292     }
293     glDeleteBuffers(1, m_textureBuffer);
294 
295     m_resources.clear();
296     m_needsInit = true;
297     GLUtils::checkGlError("cleanupGLResources");
298 
299     return;
300 }
301 
initGLResources()302 void ShaderProgram::initGLResources()
303 {
304     // To detect whether or not resources for ShaderProgram allocated
305     // successfully, we clean up pre-existing errors here and will check for
306     // new errors at the end of this function.
307     GLUtils::checkGlError("before initGLResources");
308 
309     GLint tex2DProgram = createProgram(gVertexShader, gFragmentShader);
310     GLint pureColorProgram = createProgram(gPureColorVertexShader, gPureColorFragmentShader);
311     GLint tex2DInvProgram = createProgram(gVertexShader, gFragmentShaderInverted);
312     GLint videoProgram = createProgram(gVideoVertexShader, gVideoFragmentShader);
313     GLint texOESProgram =
314         createProgram(gVertexShader, gSurfaceTextureOESFragmentShader);
315     GLint texOESInvProgram =
316         createProgram(gVertexShader, gSurfaceTextureOESFragmentShaderInverted);
317     GLint repeatTexProgram =
318         createProgram(gVertexShader, gRepeatTexFragmentShader);
319     GLint repeatTexInvProgram =
320         createProgram(gVertexShader, gRepeatTexFragmentShaderInverted);
321 
322     if (tex2DProgram == -1
323         || pureColorProgram == -1
324         || tex2DInvProgram == -1
325         || videoProgram == -1
326         || texOESProgram == -1
327         || texOESInvProgram == -1
328         || repeatTexProgram == -1
329         || repeatTexInvProgram == -1) {
330         m_needsInit = true;
331         return;
332     }
333 
334     GLint pureColorPosition = glGetAttribLocation(pureColorProgram, "vPosition");
335     GLint pureColorProjMtx = glGetUniformLocation(pureColorProgram, "projectionMatrix");
336     GLint pureColorValue = glGetUniformLocation(pureColorProgram, "inputColor");
337     m_handleArray[PureColor].init(-1, -1, pureColorPosition, pureColorProgram,
338                                   pureColorProjMtx, pureColorValue, -1, -1, -1, -1);
339     initProgram(PureColor);
340 
341     GLint tex2DAlpha = glGetUniformLocation(tex2DProgram, "alpha");
342     GLint tex2DPosition = glGetAttribLocation(tex2DProgram, "vPosition");
343     GLint tex2DProjMtx = glGetUniformLocation(tex2DProgram, "projectionMatrix");
344     GLint tex2DTexSampler = glGetUniformLocation(tex2DProgram, "s_texture");
345     GLint tex2DFillPortion = glGetUniformLocation(tex2DProgram, "fillPortion");
346     m_handleArray[Tex2D].init(tex2DAlpha, -1, tex2DPosition, tex2DProgram,
347                               tex2DProjMtx, -1, tex2DTexSampler, -1, tex2DFillPortion, -1);
348     initProgram(Tex2D);
349 
350     GLint tex2DInvAlpha = glGetUniformLocation(tex2DInvProgram, "alpha");
351     GLint tex2DInvContrast = glGetUniformLocation(tex2DInvProgram, "contrast");
352     GLint tex2DInvPosition = glGetAttribLocation(tex2DInvProgram, "vPosition");
353     GLint tex2DInvProjMtx = glGetUniformLocation(tex2DInvProgram, "projectionMatrix");
354     GLint tex2DInvTexSampler = glGetUniformLocation(tex2DInvProgram, "s_texture");
355     GLint tex2DInvFillPortion = glGetUniformLocation(tex2DInvProgram, "fillPortion");
356     m_handleArray[Tex2DInv].init(tex2DInvAlpha, tex2DInvContrast,
357                                  tex2DInvPosition, tex2DInvProgram,
358                                  tex2DInvProjMtx, -1,
359                                  tex2DInvTexSampler, -1, tex2DInvFillPortion, -1);
360     initProgram(Tex2DInv);
361 
362     GLint repeatTexAlpha = glGetUniformLocation(repeatTexProgram, "alpha");
363     GLint repeatTexPosition = glGetAttribLocation(repeatTexProgram, "vPosition");
364     GLint repeatTexProjMtx = glGetUniformLocation(repeatTexProgram, "projectionMatrix");
365     GLint repeatTexTexSampler = glGetUniformLocation(repeatTexProgram, "s_texture");
366     GLint repeatTexFillPortion = glGetUniformLocation(repeatTexProgram, "fillPortion");
367     GLint repeatTexScale = glGetUniformLocation(repeatTexProgram, "repeatScale");
368     m_handleArray[RepeatTex].init(repeatTexAlpha, -1, repeatTexPosition,
369                                   repeatTexProgram,repeatTexProjMtx, -1,
370                                   repeatTexTexSampler, -1, repeatTexFillPortion,
371                                   repeatTexScale);
372     initProgram(RepeatTex);
373 
374     GLint repeatTexInvAlpha = glGetUniformLocation(repeatTexInvProgram, "alpha");
375     GLint repeatTexInvContrast = glGetUniformLocation(tex2DInvProgram, "contrast");
376     GLint repeatTexInvPosition = glGetAttribLocation(repeatTexInvProgram, "vPosition");
377     GLint repeatTexInvProjMtx = glGetUniformLocation(repeatTexInvProgram, "projectionMatrix");
378     GLint repeatTexInvTexSampler = glGetUniformLocation(repeatTexInvProgram, "s_texture");
379     GLint repeatTexInvFillPortion = glGetUniformLocation(repeatTexInvProgram, "fillPortion");
380     GLint repeatTexInvScale = glGetUniformLocation(repeatTexInvProgram, "repeatScale");
381     m_handleArray[RepeatTexInv].init(repeatTexInvAlpha, repeatTexInvContrast,
382                                      repeatTexInvPosition, repeatTexInvProgram,
383                                      repeatTexInvProjMtx, -1,
384                                      repeatTexInvTexSampler, -1,
385                                      repeatTexInvFillPortion, repeatTexInvScale);
386     initProgram(RepeatTexInv);
387 
388     GLint texOESAlpha = glGetUniformLocation(texOESProgram, "alpha");
389     GLint texOESPosition = glGetAttribLocation(texOESProgram, "vPosition");
390     GLint texOESProjMtx = glGetUniformLocation(texOESProgram, "projectionMatrix");
391     GLint texOESTexSampler = glGetUniformLocation(texOESProgram, "s_texture");
392     GLint texOESFillPortion = glGetUniformLocation(texOESProgram, "fillPortion");
393     m_handleArray[TexOES].init(texOESAlpha, -1, texOESPosition, texOESProgram,
394                                texOESProjMtx, -1, texOESTexSampler, -1, texOESFillPortion, -1);
395     initProgram(TexOES);
396 
397     GLint texOESInvAlpha = glGetUniformLocation(texOESInvProgram, "alpha");
398     GLint texOESInvContrast = glGetUniformLocation(texOESInvProgram, "contrast");
399     GLint texOESInvPosition = glGetAttribLocation(texOESInvProgram, "vPosition");
400     GLint texOESInvProjMtx = glGetUniformLocation(texOESInvProgram, "projectionMatrix");
401     GLint texOESInvTexSampler = glGetUniformLocation(texOESInvProgram, "s_texture");
402     GLint texOESInvFillPortion = glGetUniformLocation(texOESInvProgram, "fillPortion");
403     m_handleArray[TexOESInv].init(texOESInvAlpha, texOESInvContrast,
404                                   texOESInvPosition, texOESInvProgram,
405                                   texOESInvProjMtx, -1,
406                                   texOESInvTexSampler, -1, texOESInvFillPortion, -1);
407     initProgram(TexOESInv);
408 
409     GLint videoPosition = glGetAttribLocation(videoProgram, "vPosition");
410     GLint videoProjMtx = glGetUniformLocation(videoProgram, "projectionMatrix");
411     GLint videoTexSampler = glGetUniformLocation(videoProgram, "s_yuvTexture");
412     GLint videoTexMtx = glGetUniformLocation(videoProgram, "textureMatrix");
413     m_handleArray[Video].init(-1, -1, videoPosition, videoProgram,
414                               videoProjMtx, -1, videoTexSampler,
415                               videoTexMtx, -1, -1);
416     initProgram(Video);
417 
418     const GLfloat coord[] = {
419         0.0f, 0.0f, // C
420         1.0f, 0.0f, // D
421         0.0f, 1.0f, // A
422         1.0f, 1.0f // B
423     };
424 
425     glGenBuffers(1, m_textureBuffer);
426     glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]);
427     glBufferData(GL_ARRAY_BUFFER, 2 * 4 * sizeof(GLfloat), coord, GL_STATIC_DRAW);
428 
429     TransformationMatrix matrix;
430     // Map x,y from (0,1) to (-1, 1)
431     matrix.scale3d(2, 2, 1);
432     matrix.translate3d(-0.5, -0.5, 0);
433     GLUtils::toGLMatrix(m_transferProjMtx, matrix);
434 
435     m_needsInit = GLUtils::checkGlError("initGLResources");
436     return;
437 }
438 
resetBlending()439 void ShaderProgram::resetBlending()
440 {
441     glDisable(GL_BLEND);
442     glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
443     glBlendEquation(GL_FUNC_ADD);
444     m_blendingEnabled = false;
445 }
446 
setBlendingState(bool enableBlending)447 void ShaderProgram::setBlendingState(bool enableBlending)
448 {
449     if (enableBlending == m_blendingEnabled)
450         return;
451 
452     if (enableBlending)
453         glEnable(GL_BLEND);
454     else
455         glDisable(GL_BLEND);
456 
457     m_blendingEnabled = enableBlending;
458 }
459 
460 /////////////////////////////////////////////////////////////////////////////////////////
461 // Drawing
462 /////////////////////////////////////////////////////////////////////////////////////////
463 
464 // We have multiple coordinates to deal with: first is the screen coordinates,
465 // second is the view coordinates and the last one is content(document) coordinates.
466 // Both screen and view coordinates are in pixels.
467 // All these coordinates start from upper left, but for the purpose of OpenGL
468 // operations, we may need a inverted Y version of such coordinates which
469 // start from lower left.
470 //
471 // invScreenRect - inv screen coordinates starting from lower left.
472 // visibleContentRect - local content(document) coordinates starting from upper left.
473 // screenRect - screen coordinates starting from upper left.
474 // screenClip - screen coordinates starting from upper left.
475 //    ------------------------------------------
476 //    |(origin of screen)                      |
477 //    |screen                                  |
478 //    |   ---------------------------------    |
479 //    |   | (origin of view)              |    |
480 //    |   | webview                       |    |
481 //    |   |        --------               |    |
482 //    |   |        | clip |               |    |
483 //    |   |        |      |               |    |
484 //    |   |        --------               |    |
485 //    |   |                               |    |
486 //    |   |(origin of inv view)           |    |
487 //    |   ---------------------------------    |
488 //    |(origin of inv screen)                  |
489 //    ------------------------------------------
setupDrawing(const IntRect & invScreenRect,const SkRect & visibleContentRect,const IntRect & screenRect,int titleBarHeight,const IntRect & screenClip,float scale)490 void ShaderProgram::setupDrawing(const IntRect& invScreenRect,
491                                  const SkRect& visibleContentRect,
492                                  const IntRect& screenRect, int titleBarHeight,
493                                  const IntRect& screenClip, float scale)
494 {
495     m_screenRect = screenRect;
496     m_titleBarHeight = titleBarHeight;
497 
498     //// viewport ////
499     GLUtils::setOrthographicMatrix(m_visibleContentRectProjectionMatrix,
500                                    visibleContentRect.fLeft,
501                                    visibleContentRect.fTop,
502                                    visibleContentRect.fRight,
503                                    visibleContentRect.fBottom,
504                                    -1000, 1000);
505 
506     ALOGV("set m_clipProjectionMatrix, %d, %d, %d, %d",
507           screenClip.x(), screenClip.y(), screenClip.x() + screenClip.width(),
508           screenClip.y() + screenClip.height());
509 
510     // In order to incorporate the animation delta X and Y, using the clip as
511     // the GL viewport can save all the trouble of re-position from screenRect
512     // to final position.
513     GLUtils::setOrthographicMatrix(m_clipProjectionMatrix, screenClip.x(), screenClip.y(),
514                                    screenClip.x() + screenClip.width(),
515                                    screenClip.y() + screenClip.height(), -1000, 1000);
516 
517     glViewport(screenClip.x(), m_targetHeight - screenClip.y() - screenClip.height() ,
518                screenClip.width(), screenClip.height());
519 
520     m_visibleContentRect = visibleContentRect;
521     m_currentScale = scale;
522 
523 
524     //// viewRect ////
525     m_invScreenRect = invScreenRect;
526 
527     // The following matrices transform content coordinates into view coordinates
528     // and inv view coordinates.
529     // Note that GLUtils::setOrthographicMatrix is inverting the Y.
530     TransformationMatrix viewTranslate;
531     viewTranslate.translate(1.0, 1.0);
532 
533     TransformationMatrix viewScale;
534     viewScale.scale3d(m_invScreenRect.width() * 0.5f, m_invScreenRect.height() * 0.5f, 1);
535 
536     m_contentToInvViewMatrix = viewScale * viewTranslate * m_visibleContentRectProjectionMatrix;
537 
538     viewTranslate.scale3d(1, -1, 1);
539     m_contentToViewMatrix = viewScale * viewTranslate * m_visibleContentRectProjectionMatrix;
540 
541     IntRect invViewRect(0, 0, m_screenRect.width(), m_screenRect.height());
542     m_contentViewport = m_contentToInvViewMatrix.inverse().mapRect(invViewRect);
543 
544 
545     //// clipping ////
546     IntRect viewClip = screenClip;
547 
548     // The incoming screenClip is in screen coordinates, we first
549     // translate it into view coordinates.
550     // Then we convert it into inverted view coordinates.
551     // Therefore, in the clip() function, we need to convert things back from
552     // inverted view coordinates to inverted screen coordinates which is used by GL.
553     viewClip.setX(screenClip.x() - m_screenRect.x());
554     viewClip.setY(screenClip.y() - m_screenRect.y() - m_titleBarHeight);
555     FloatRect invViewClip = convertViewCoordToInvViewCoord(viewClip);
556     m_invViewClip.setLocation(IntPoint(invViewClip.x(), invViewClip.y()));
557     // use ceilf to handle view -> doc -> view coord rounding errors
558     m_invViewClip.setSize(IntSize(ceilf(invViewClip.width()), ceilf(invViewClip.height())));
559 
560     resetBlending();
561 
562     // Set up m_clipProjectionMatrix, m_currentScale and m_webViewMatrix before
563     // calling this function.
564     setupSurfaceProjectionMatrix();
565 
566     //// initialize frame-constant values ////
567     glActiveTexture(GL_TEXTURE0);
568     glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]);
569 
570     //// initialize GL cache ////
571     m_cachedProgramType = UndefinedShader;
572     m_cachedOpacity = -1;
573     m_cachedFillPortion = FloatRect();
574     m_cachedPureColor = Color();
575 }
576 
577 // Calculate the right color value sent into the shader considering the (0,1)
578 // clamp and alpha blending.
shaderColor(Color pureColor,float opacity)579 Color ShaderProgram::shaderColor(Color pureColor, float opacity)
580 {
581     float r = pureColor.red() / 255.0;
582     float g = pureColor.green() / 255.0;
583     float b = pureColor.blue() / 255.0;
584     float a = pureColor.alpha() / 255.0;
585 
586     if (TilesManager::instance()->invertedScreen()) {
587         float intensity = a - (0.2989 * r + 0.5866 * g + 0.1145 * b);
588         intensity = ((intensity - a / 2.0) * m_contrast) + a / 2.0;
589         intensity *= opacity;
590         return Color(intensity, intensity, intensity, a * opacity);
591     }
592     return Color(r * opacity, g * opacity, b * opacity, a * opacity);
593 }
594 
595 // For shaders using texture, it is easy to get the type from the textureTarget.
getTextureShaderType(GLenum textureTarget,bool hasRepeatScale)596 ShaderType ShaderProgram::getTextureShaderType(GLenum textureTarget,
597                                                bool hasRepeatScale)
598 {
599     ShaderType type = UndefinedShader;
600     if (textureTarget == GL_TEXTURE_2D) {
601         if (!TilesManager::instance()->invertedScreen())
602             type = hasRepeatScale ?  RepeatTex : Tex2D;
603         else {
604             // With the new GPU texture upload path, we do not use an FBO
605             // to blit the texture we receive from the TexturesGenerator thread.
606             // To implement inverted rendering, we thus have to do the rendering
607             // live, by using a different shader.
608             type = hasRepeatScale ?  RepeatTexInv : Tex2DInv;
609         }
610     } else if (textureTarget == GL_TEXTURE_EXTERNAL_OES) {
611         if (!TilesManager::instance()->invertedScreen())
612             type = TexOES;
613         else
614             type = TexOESInv;
615     }
616     return type;
617 }
618 
619 // This function transform a clip rect extracted from the current layer
620 // into a clip rect in InvView coordinates -- used by the clipping rects
rectInInvViewCoord(const TransformationMatrix & drawMatrix,const IntSize & size)621 FloatRect ShaderProgram::rectInInvViewCoord(const TransformationMatrix& drawMatrix, const IntSize& size)
622 {
623     FloatRect srect(0, 0, size.width(), size.height());
624     TransformationMatrix renderMatrix = m_contentToInvViewMatrix * drawMatrix;
625     return renderMatrix.mapRect(srect);
626 }
627 
628 // used by the partial screen invals
rectInViewCoord(const TransformationMatrix & drawMatrix,const IntSize & size)629 FloatRect ShaderProgram::rectInViewCoord(const TransformationMatrix& drawMatrix, const IntSize& size)
630 {
631     FloatRect srect(0, 0, size.width(), size.height());
632     TransformationMatrix renderMatrix = m_contentToViewMatrix * drawMatrix;
633     return renderMatrix.mapRect(srect);
634 }
635 
rectInViewCoord(const FloatRect & rect)636 FloatRect ShaderProgram::rectInViewCoord(const FloatRect& rect)
637 {
638     return m_contentToViewMatrix.mapRect(rect);
639 }
640 
rectInInvViewCoord(const FloatRect & rect)641 FloatRect ShaderProgram::rectInInvViewCoord(const FloatRect& rect)
642 {
643     return m_contentToInvViewMatrix.mapRect(rect);
644 }
645 
convertInvViewCoordToContentCoord(const FloatRect & rect)646 FloatRect ShaderProgram::convertInvViewCoordToContentCoord(const FloatRect& rect)
647 {
648     return m_contentToInvViewMatrix.inverse().mapRect(rect);
649 }
650 
convertViewCoordToInvViewCoord(const FloatRect & rect)651 FloatRect ShaderProgram::convertViewCoordToInvViewCoord(const FloatRect& rect)
652 {
653     FloatRect visibleContentRect = m_contentToViewMatrix.inverse().mapRect(rect);
654     return rectInInvViewCoord(visibleContentRect);
655 }
656 
convertInvViewCoordToViewCoord(const FloatRect & rect)657 FloatRect ShaderProgram::convertInvViewCoordToViewCoord(const FloatRect& rect)
658 {
659     FloatRect visibleContentRect = m_contentToInvViewMatrix.inverse().mapRect(rect);
660     return rectInViewCoord(visibleContentRect);
661 }
662 
663 // clip is in screen coordinates
clip(const FloatRect & clip)664 void ShaderProgram::clip(const FloatRect& clip)
665 {
666     if (clip == m_clipRect)
667         return;
668 
669     ALOGV("--clipping rect %f %f, %f x %f",
670           clip.x(), clip.y(), clip.width(), clip.height());
671 
672     // we should only call glScissor in this function, so that we can easily
673     // track the current clipping rect.
674 
675     IntRect screenClip(clip.x(),
676                        clip.y(),
677                        clip.width(), clip.height());
678 
679     if (!m_invViewClip.isEmpty())
680         screenClip.intersect(m_invViewClip);
681 
682     // The previous intersection calculation is using local screen coordinates.
683     // Now we need to convert things from local screen coordinates to global
684     // screen coordinates and pass to the GL functions.
685     screenClip.setX(screenClip.x() + m_invScreenRect.x());
686     screenClip.setY(screenClip.y() + m_invScreenRect.y());
687     if (screenClip.x() < 0) {
688         int w = screenClip.width();
689         w += screenClip.x();
690         screenClip.setX(0);
691         screenClip.setWidth(w);
692     }
693     if (screenClip.y() < 0) {
694         int h = screenClip.height();
695         h += screenClip.y();
696         screenClip.setY(0);
697         screenClip.setHeight(h);
698     }
699 
700     glScissor(screenClip.x(), screenClip.y(), screenClip.width(), screenClip.height());
701 
702     m_clipRect = clip;
703 }
704 
clippedRectWithVisibleContentRect(const IntRect & rect,int margin)705 IntRect ShaderProgram::clippedRectWithVisibleContentRect(const IntRect& rect, int margin)
706 {
707     IntRect viewport(m_visibleContentRect.fLeft - margin, m_visibleContentRect.fTop - margin,
708                      m_visibleContentRect.width() + margin,
709                      m_visibleContentRect.height() + margin);
710     viewport.intersect(rect);
711     return viewport;
712 }
713 
zValue(const TransformationMatrix & drawMatrix,float w,float h)714 float ShaderProgram::zValue(const TransformationMatrix& drawMatrix, float w, float h)
715 {
716     TransformationMatrix modifiedDrawMatrix = drawMatrix;
717     modifiedDrawMatrix.scale3d(w, h, 1);
718     TransformationMatrix renderMatrix =
719         m_visibleContentRectProjectionMatrix * modifiedDrawMatrix;
720     FloatPoint3D point(0.5, 0.5, 0.0);
721     FloatPoint3D result = renderMatrix.mapPoint(point);
722     return result.z();
723 }
724 
drawQuadInternal(ShaderType type,const GLfloat * matrix,int textureId,float opacity,GLenum textureTarget,GLenum filter,const Color & pureColor,const FloatRect & fillPortion,const FloatSize & repeatScale)725 void ShaderProgram::drawQuadInternal(ShaderType type, const GLfloat* matrix,
726                                      int textureId, float opacity,
727                                      GLenum textureTarget, GLenum filter,
728                                      const Color& pureColor, const FloatRect& fillPortion,
729                                      const FloatSize& repeatScale)
730 {
731     if (m_cachedProgramType != type) {
732         glUseProgram(m_handleArray[type].programHandle);
733         glVertexAttribPointer(m_handleArray[type].positionHandle,
734                               2, GL_FLOAT, GL_FALSE, 0, 0);
735         m_cachedProgramType = type;
736         m_cachedFillPortion = FloatRect();
737         m_cachedOpacity = -1; // reset cache for variable shared by multiple programs
738     }
739     glUniformMatrix4fv(m_handleArray[type].projMtxHandle, 1, GL_FALSE, matrix);
740 
741     if (type != PureColor) {
742         glBindTexture(textureTarget, textureId);
743         glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, filter);
744         glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, filter);
745 
746         if (m_cachedOpacity != opacity) {
747             glUniform1f(m_handleArray[type].alphaHandle, opacity);
748             m_cachedOpacity = opacity;
749         }
750 
751         GLint contrastHandle = m_handleArray[type].contrastHandle;
752         if (contrastHandle != -1)
753             glUniform1f(contrastHandle, m_contrast);
754 
755         if (m_cachedFillPortion != fillPortion) {
756             glUniform4f(m_handleArray[type].fillPortionHandle, fillPortion.x(), fillPortion.y(),
757                         fillPortion.width(), fillPortion.height());
758             m_cachedFillPortion = fillPortion;
759         }
760 
761         // Only when we have repeat scale, this handle can be >= 0;
762         if (m_handleArray[type].scaleHandle != -1) {
763             glUniform2f(m_handleArray[type].scaleHandle,
764                         repeatScale.width(), repeatScale.height());
765         }
766     } else {
767         if (m_cachedPureColor != pureColor) {
768             glUniform4f(m_handleArray[type].pureColorHandle,
769                         pureColor.red() / 255.0, pureColor.green() / 255.0,
770                         pureColor.blue() / 255.0, pureColor.alpha() / 255.0);
771             m_cachedPureColor = pureColor;
772         }
773     }
774 
775     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
776 }
777 
778 // Put the common matrix computation at higher level to avoid redundancy.
setupSurfaceProjectionMatrix()779 void ShaderProgram::setupSurfaceProjectionMatrix()
780 {
781     TransformationMatrix scaleMatrix;
782     scaleMatrix.scale3d(m_currentScale, m_currentScale, 1);
783     m_surfaceProjectionMatrix = m_clipProjectionMatrix * m_webViewMatrix * scaleMatrix;
784 }
785 
786 // Calculate the matrix given the geometry.
getTileProjectionMatrix(const DrawQuadData * data)787 GLfloat* ShaderProgram::getTileProjectionMatrix(const DrawQuadData* data)
788 {
789     DrawQuadType type = data->type();
790     if (type == Blit)
791         return m_transferProjMtx;
792 
793     const TransformationMatrix* matrix = data->drawMatrix();
794     const SkRect* geometry = data->geometry();
795     FloatRect fillPortion = data->fillPortion();
796     ALOGV("fillPortion " FLOAT_RECT_FORMAT, FLOAT_RECT_ARGS(fillPortion));
797 
798     // This modifiedDrawMatrix tranform (0,0)(1x1) to the final rect in screen
799     // coordinates, before applying the m_webViewMatrix.
800     // It first scale and translate the vertex array from (0,0)(1x1) to real
801     // tile position and size. Then apply the transform from the layer's.
802     // Finally scale to the currentScale to support zooming.
803     // Note the geometry contains the tile zoom scale, so visually we will see
804     // the tiles scale at a ratio as (m_currentScale/tile's scale).
805     TransformationMatrix modifiedDrawMatrix;
806     if (type == LayerQuad)
807         modifiedDrawMatrix = *matrix;
808     modifiedDrawMatrix.translate(geometry->fLeft + geometry->width() * fillPortion.x(),
809                                  geometry->fTop + geometry->height() * fillPortion.y());
810     modifiedDrawMatrix.scale3d(geometry->width() * fillPortion.width(),
811                                geometry->height() * fillPortion.height(), 1);
812 
813     // Even when we are on a alpha layer or not, we need to respect the
814     // m_webViewMatrix, it may contain the layout offset. Normally it is
815     // identity.
816     TransformationMatrix renderMatrix;
817     renderMatrix = m_surfaceProjectionMatrix * modifiedDrawMatrix;
818 
819 #if DEBUG_MATRIX
820     debugMatrixInfo(m_currentScale, m_clipProjectionMatrix, m_webViewMatrix,
821                     modifiedDrawMatrix, matrix);
822 #endif
823 
824     GLUtils::toGLMatrix(m_tileProjMatrix, renderMatrix);
825     return m_tileProjMatrix;
826 }
827 
drawQuad(const DrawQuadData * data)828 void ShaderProgram::drawQuad(const DrawQuadData* data)
829 {
830     GLfloat* matrix = getTileProjectionMatrix(data);
831 
832     float opacity = data->opacity();
833     bool forceBlending = data->forceBlending();
834     bool enableBlending = forceBlending || opacity < 1.0;
835 
836     ShaderType shaderType = UndefinedShader;
837     int textureId = 0;
838     GLint textureFilter = 0;
839     GLenum textureTarget = 0;
840 
841     Color quadColor = data->quadColor();
842     if (data->pureColor()) {
843         shaderType = PureColor;
844         quadColor = shaderColor(quadColor, opacity);
845         enableBlending = enableBlending || quadColor.hasAlpha();
846         if (!quadColor.alpha() && enableBlending)
847             return;
848     } else {
849         textureId = data->textureId();
850         textureFilter = data->textureFilter();
851         textureTarget = data->textureTarget();
852         shaderType = getTextureShaderType(textureTarget, data->hasRepeatScale());
853     }
854     setBlendingState(enableBlending);
855     drawQuadInternal(shaderType, matrix, textureId, opacity,
856                      textureTarget, textureFilter, quadColor, data->fillPortion(),
857                      data->repeatScale());
858 }
859 
drawVideoLayerQuad(const TransformationMatrix & drawMatrix,float * textureMatrix,SkRect & geometry,int textureId)860 void ShaderProgram::drawVideoLayerQuad(const TransformationMatrix& drawMatrix,
861                                        float* textureMatrix, SkRect& geometry,
862                                        int textureId)
863 {
864     // switch to our custom yuv video rendering program
865     if (m_cachedProgramType != Video) {
866         glUseProgram(m_handleArray[Video].programHandle);
867         glVertexAttribPointer(m_handleArray[Video].positionHandle,
868                               2, GL_FLOAT, GL_FALSE, 0, 0);
869         m_cachedProgramType = Video;
870     }
871 
872     // TODO: Merge drawVideoLayerQuad into drawQuad.
873     TransformationMatrix modifiedDrawMatrix;
874     modifiedDrawMatrix.scale3d(m_currentScale, m_currentScale, 1);
875     modifiedDrawMatrix.multiply(drawMatrix);
876     modifiedDrawMatrix.translate(geometry.fLeft, geometry.fTop);
877     modifiedDrawMatrix.scale3d(geometry.width(), geometry.height(), 1);
878     TransformationMatrix renderMatrix =
879         m_clipProjectionMatrix * m_webViewMatrix * modifiedDrawMatrix;
880 
881     GLfloat projectionMatrix[16];
882     GLUtils::toGLMatrix(projectionMatrix, renderMatrix);
883     glUniformMatrix4fv(m_handleArray[Video].projMtxHandle, 1, GL_FALSE,
884                        projectionMatrix);
885     glUniformMatrix4fv(m_handleArray[Video].videoMtxHandle, 1, GL_FALSE,
886                        textureMatrix);
887     glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureId);
888 
889     setBlendingState(false);
890     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
891 }
892 
setGLDrawInfo(const android::uirenderer::DrawGlInfo * info)893 void ShaderProgram::setGLDrawInfo(const android::uirenderer::DrawGlInfo* info)
894 {
895     GLUtils::convertToTransformationMatrix(info->transform, m_webViewMatrix);
896     m_alphaLayer = info->isLayer;
897     m_targetHeight = info->height;
898 }
899 
900 // This function is called per tileGrid to minimize the computation overhead.
901 // The ortho projection and glViewport will map 1:1, so we don't need to
902 // worry about them here. Basically, if the current zoom scale / tile's scale
903 // plus the webview and layer transformation ends up at scale factor 1.0,
904 // then we can use point sampling.
usePointSampling(float tileScale,const TransformationMatrix * layerTransform)905 bool ShaderProgram::usePointSampling(float tileScale,
906                                      const TransformationMatrix* layerTransform)
907 {
908     const float testSize = 1.0;
909     FloatRect rect(0, 0, testSize, testSize);
910     TransformationMatrix matrix;
911     matrix.scale3d(m_currentScale, m_currentScale, 1);
912     if (layerTransform)
913         matrix.multiply(*layerTransform);
914     matrix.scale3d(1.0 / tileScale, 1.0 / tileScale, 1);
915 
916     matrix = m_webViewMatrix * matrix;
917 
918     rect = matrix.mapRect(rect);
919 
920     float deltaWidth = abs(rect.width() - testSize);
921     float deltaHeight = abs(rect.height() - testSize);
922 
923     if (deltaWidth < EPSILON && deltaHeight < EPSILON) {
924         ALOGV("Point sampling : deltaWidth is %f, deltaHeight is %f", deltaWidth, deltaHeight);
925         return true;
926     }
927     return false;
928 }
929 
930 #if DEBUG_MATRIX
debugMatrixTransform(const TransformationMatrix & matrix,const char * matrixName)931 FloatRect ShaderProgram::debugMatrixTransform(const TransformationMatrix& matrix,
932                                               const char* matrixName)
933 {
934     FloatRect rect(0.0, 0.0, 1.0, 1.0);
935     rect = matrix.mapRect(rect);
936     ALOGV("After %s matrix:\n %f, %f rect.width() %f rect.height() %f",
937           matrixName, rect.x(), rect.y(), rect.width(), rect.height());
938     return rect;
939 
940 }
941 
debugMatrixInfo(float currentScale,const TransformationMatrix & clipProjectionMatrix,const TransformationMatrix & webViewMatrix,const TransformationMatrix & modifiedDrawMatrix,const TransformationMatrix * layerMatrix)942 void ShaderProgram::debugMatrixInfo(float currentScale,
943                                     const TransformationMatrix& clipProjectionMatrix,
944                                     const TransformationMatrix& webViewMatrix,
945                                     const TransformationMatrix& modifiedDrawMatrix,
946                                     const TransformationMatrix* layerMatrix)
947 {
948     int viewport[4];
949     glGetIntegerv(GL_VIEWPORT, viewport);
950     ALOGV("viewport %d, %d, %d, %d , currentScale %f",
951           viewport[0], viewport[1], viewport[2], viewport[3], currentScale);
952     IntRect currentGLViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
953 
954     TransformationMatrix scaleMatrix;
955     scaleMatrix.scale3d(currentScale, currentScale, 1.0);
956 
957     if (layerMatrix)
958         debugMatrixTransform(*layerMatrix, "layerMatrix");
959 
960     TransformationMatrix debugMatrix = scaleMatrix * modifiedDrawMatrix;
961     debugMatrixTransform(debugMatrix, "scaleMatrix * modifiedDrawMatrix");
962 
963     debugMatrix = webViewMatrix * debugMatrix;
964     debugMatrixTransform(debugMatrix, "webViewMatrix * scaleMatrix * modifiedDrawMatrix");
965 
966     debugMatrix = clipProjectionMatrix * debugMatrix;
967     FloatRect finalRect =
968         debugMatrixTransform(debugMatrix, "all Matrix");
969     // After projection, we will be in a (-1, 1) range and now we can map it back
970     // to the (x,y) -> (x+width, y+height)
971     ALOGV("final convert to screen coord x, y %f, %f width %f height %f , ",
972           (finalRect.x() + 1) / 2 * currentGLViewport.width() + currentGLViewport.x(),
973           (finalRect.y() + 1) / 2 * currentGLViewport.height() + currentGLViewport.y(),
974           finalRect.width() * currentGLViewport.width() / 2,
975           finalRect.height() * currentGLViewport.height() / 2);
976 }
977 #endif // DEBUG_MATRIX
978 
979 } // namespace WebCore
980 #endif // USE(ACCELERATED_COMPOSITING)
981