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