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