1/* 2 * Copyright (C) 2010, 2011, 2012, 2013 Research In Motion Limited. All rights reserved. 3 * Copyright (C) 2010 Google Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 33#include "config.h" 34 35#if USE(ACCELERATED_COMPOSITING) 36#include "LayerRenderer.h" 37 38#include "LayerCompositingThread.h" 39#include "LayerFilterRenderer.h" 40#include "LayerRendererClient.h" 41#include "TextureCacheCompositingThread.h" 42 43#include <BlackBerryPlatformGraphics.h> 44#include <BlackBerryPlatformLog.h> 45#include <EGL/egl.h> 46#include <limits> 47#include <wtf/text/CString.h> 48#include <wtf/text/WTFString.h> 49 50#define DEBUG_LAYER_ANIMATIONS 0 // Show running animations as green. 51#define DEBUG_CLIPPING 0 52 53using BlackBerry::Platform::Graphics::GLES2Context; 54using BlackBerry::Platform::Graphics::GLES2Program; 55using namespace std; 56 57namespace WebCore { 58 59#ifndef NDEBUG 60#define checkGLError() \ 61{ \ 62 if (GLenum error = glGetError()) \ 63 BlackBerry::Platform::logAlways(BlackBerry::Platform::LogLevelCritical, "%s:%d GL Error: 0x%x ", __FILE__, __LINE__, error); \ 64} 65#else 66#define checkGLError() 67#endif 68 69GLuint LayerRenderer::loadShader(GLenum type, const char* shaderSource) 70{ 71 GLuint shader = glCreateShader(type); 72 if (!shader) 73 return 0; 74 glShaderSource(shader, 1, &shaderSource, 0); 75 glCompileShader(shader); 76 GLint compiled; 77 glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); 78 if (!compiled) { 79 char infoLog[2048]; 80 GLsizei length; 81 glGetShaderInfoLog(shader, 2048, &length, infoLog); 82 BlackBerry::Platform::logAlways(BlackBerry::Platform::LogLevelCritical, "Failed to compile shader:\n%s\nlog: %s", shaderSource, infoLog); 83 glDeleteShader(shader); 84 return 0; 85 } 86 return shader; 87} 88 89GLuint LayerRenderer::loadShaderProgram(const char* vertexShaderSource, const char* fragmentShaderSource) 90{ 91 GLuint vertexShader; 92 GLuint fragmentShader; 93 GLuint programObject; 94 GLint linked; 95 vertexShader = loadShader(GL_VERTEX_SHADER, vertexShaderSource); 96 if (!vertexShader) 97 return 0; 98 fragmentShader = loadShader(GL_FRAGMENT_SHADER, fragmentShaderSource); 99 if (!fragmentShader) { 100 glDeleteShader(vertexShader); 101 return 0; 102 } 103 programObject = glCreateProgram(); 104 if (programObject) { 105 glAttachShader(programObject, vertexShader); 106 glAttachShader(programObject, fragmentShader); 107 glLinkProgram(programObject); 108 glGetProgramiv(programObject, GL_LINK_STATUS, &linked); 109 if (!linked) { 110 glDeleteProgram(programObject); 111 programObject = 0; 112 } 113 } 114 glDeleteShader(vertexShader); 115 glDeleteShader(fragmentShader); 116 return programObject; 117} 118 119TransformationMatrix LayerRenderer::orthoMatrix(float left, float right, float bottom, float top, float nearZ, float farZ) 120{ 121 float deltaX = right - left; 122 float deltaY = top - bottom; 123 float deltaZ = farZ - nearZ; 124 TransformationMatrix ortho; 125 if (!deltaX || !deltaY || !deltaZ) 126 return ortho; 127 ortho.setM11(2.0f / deltaX); 128 ortho.setM41(-(right + left) / deltaX); 129 ortho.setM22(2.0f / deltaY); 130 ortho.setM42(-(top + bottom) / deltaY); 131 ortho.setM33(-2.0f / deltaZ); 132 ortho.setM43(-(nearZ + farZ) / deltaZ); 133 return ortho; 134} 135 136static Vector<LayerCompositingThread*> rawPtrVectorFromRefPtrVector(const Vector<RefPtr<LayerCompositingThread> >& sublayers) 137{ 138 Vector<LayerCompositingThread*> sublayerList; 139 for (size_t i = 0; i < sublayers.size(); i++) 140 sublayerList.append(sublayers[i].get()); 141 142 return sublayerList; 143} 144 145PassOwnPtr<LayerRenderer> LayerRenderer::create(LayerRendererClient* client) 146{ 147 return adoptPtr(new LayerRenderer(client)); 148} 149 150LayerRenderer::LayerRenderer(LayerRendererClient* client) 151 : m_client(client) 152 , m_scale(1.0) 153 , m_animationTime(-numeric_limits<double>::infinity()) 154 , m_fbo(0) 155 , m_currentLayerRendererSurface(0) 156 , m_isRobustnessSupported(false) 157 , m_needsCommit(false) 158 , m_stencilCleared(false) 159{ 160 // We're now initializing lazily, so a check if the context can be made current 161 // will have to suffice to determine if hardware compositing is possible. 162 m_hardwareCompositing = makeContextCurrent(); 163 if (m_hardwareCompositing) { 164 m_isRobustnessSupported = String(reinterpret_cast<const char*>(::glGetString(GL_EXTENSIONS))).contains("GL_EXT_robustness"); 165 if (m_isRobustnessSupported) 166 m_glGetGraphicsResetStatusEXT = reinterpret_cast<PFNGLGETGRAPHICSRESETSTATUSEXTPROC>(eglGetProcAddress("glGetGraphicsResetStatusEXT")); 167 } 168} 169 170LayerRenderer::~LayerRenderer() 171{ 172 if (m_hardwareCompositing) { 173 makeContextCurrent(); 174 if (m_fbo) 175 glDeleteFramebuffers(1, &m_fbo); 176 177 for (size_t i = 0; i < NumberOfPrograms; ++i) 178 glDeleteProgram(m_programs[i].m_program); 179 180 // Free up all GL textures. 181 while (m_layers.begin() != m_layers.end()) { 182 LayerSet::iterator iter = m_layers.begin(); 183 (*iter)->deleteTextures(); 184 (*iter)->setLayerRenderer(0); 185 removeLayer(*iter); 186 } 187 188 textureCacheCompositingThread()->clear(); 189 } 190} 191 192void LayerRenderer::releaseLayerResources() 193{ 194 if (m_hardwareCompositing) { 195 makeContextCurrent(); 196 // Free up all GL textures. 197 for (LayerSet::iterator iter = m_layers.begin(); iter != m_layers.end(); ++iter) 198 (*iter)->deleteTextures(); 199 200 textureCacheCompositingThread()->clear(); 201 } 202} 203 204static inline bool compareLayerW(const LayerCompositingThread* a, const LayerCompositingThread* b) 205{ 206 return a->centerW() > b->centerW(); 207} 208 209void LayerRenderer::prepareFrame(double animationTime, LayerCompositingThread* rootLayer) 210{ 211 if (animationTime != m_animationTime) { 212 m_animationTime = animationTime; 213 214 // Aha, new frame! Reset rendering results. 215 bool wasEmpty = m_lastRenderingResults.isEmpty(); 216 m_lastRenderingResults = LayerRenderingResults(); 217 m_lastRenderingResults.wasEmpty = wasEmpty; 218 } 219 220 if (!rootLayer) 221 return; 222 223 bool isContextCurrent = makeContextCurrent(); 224 prepareFrameRecursive(rootLayer, animationTime, isContextCurrent); 225} 226 227void LayerRenderer::setViewport(const IntRect& targetRect, const IntRect& clipRect, const FloatRect& visibleRect, const IntRect& layoutRect, const IntSize& contentsSize) 228{ 229 // These parameters are used to calculate position of fixed position elements 230 m_visibleRect = visibleRect; 231 m_layoutRect = layoutRect; 232 m_contentsSize = contentsSize; 233 234 m_viewport = targetRect; 235 m_scissorRect = clipRect; 236 237 // The clipRect parameter uses render target coordinates, map to normalized device coordinates 238 m_clipRect = clipRect; 239 m_clipRect.intersect(targetRect); 240 m_clipRect = FloatRect(-1 + 2 * (m_clipRect.x() - targetRect.x()) / targetRect.width(), 241 -1 + 2 * (m_clipRect.y() - targetRect.y()) / targetRect.height(), 242 2 * m_clipRect.width() / targetRect.width(), 243 2 * m_clipRect.height() / targetRect.height()); 244 245#if DEBUG_CLIPPING 246 printf("LayerRenderer::setViewport() m_visibleRect=(%.2f,%.2f %.2fx%.2f), m_layoutRect=(%d,%d %dx%d), m_contentsSize=(%dx%d), m_viewport=(%d,%d %dx%d), m_scissorRect=(%d,%d %dx%d), m_clipRect=(%.2f,%.2f %.2fx%.2f)\n", 247 m_visibleRect.x(), m_visibleRect.y(), m_visibleRect.width(), m_visibleRect.height(), 248 m_layoutRect.x(), m_layoutRect.y(), m_layoutRect.width(), m_layoutRect.height(), 249 m_contentsSize.width(), m_contentsSize.height(), 250 m_viewport.x(), m_viewport.y(), m_viewport.width(), m_viewport.height(), 251 m_scissorRect.x(), m_scissorRect.y(), m_scissorRect.width(), m_scissorRect.height(), 252 m_clipRect.x(), m_clipRect.y(), m_clipRect.width(), m_clipRect.height()); 253 fflush(stdout); 254#endif 255 256 if (!m_hardwareCompositing) 257 return; 258 259 // Okay, we're going to do some drawing. 260 if (!makeContextCurrent()) 261 return; 262 263 // Get rid of any bound buffer that might affect the interpretation of our 264 // glVertexAttribPointer calls. 265 glBindBuffer(GL_ARRAY_BUFFER, 0); 266 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 267 268 glActiveTexture(GL_TEXTURE0); 269 glDisable(GL_DEPTH_TEST); 270 glDisable(GL_CULL_FACE); 271 glDisable(GL_STENCIL_TEST); 272 273 // If culling is enabled then we will cull the backface. 274 glCullFace(GL_BACK); 275 276 // The BlackBerry::Platform::GraphicsContext uses OpenGL conventions, so everything is upside down 277 glFrontFace(GL_CW); 278 279 checkGLError(); 280 281 glViewport(m_viewport.x(), m_viewport.y(), m_viewport.width(), m_viewport.height()); 282 283 glEnable(GL_SCISSOR_TEST); 284#if DEBUG_CLIPPING 285 printf("LayerRenderer::compositeLayers(): clipping to (%d,%d %dx%d)\n", m_scissorRect.x(), m_scissorRect.y(), m_scissorRect.width(), m_scissorRect.height()); 286 fflush(stdout); 287#endif 288 glScissor(m_scissorRect.x(), m_scissorRect.y(), m_scissorRect.width(), m_scissorRect.height()); 289 290 m_stencilCleared = false; 291} 292 293void LayerRenderer::compositeLayers(const TransformationMatrix& matrix, LayerCompositingThread* rootLayer) 294{ 295 ASSERT(m_hardwareCompositing); 296 if (!m_hardwareCompositing) 297 return; 298 299 if (!rootLayer) 300 return; 301 302 // Used to draw scale invariant layers. We assume uniform scale. 303 // The matrix maps to normalized device coordinates, a system that maps the 304 // viewport to the interval -1 to 1. 305 // So it has to scale down by a factor equal to one half the viewport. 306 m_scale = matrix.m11() * m_viewport.width() / 2; 307 308 Vector<RefPtr<LayerCompositingThread> > surfaceLayers; 309 const Vector<RefPtr<LayerCompositingThread> >& sublayers = rootLayer->sublayers(); 310 for (size_t i = 0; i < sublayers.size(); i++) { 311 float opacity = 1; 312 FloatRect clipRect(m_clipRect); 313 updateLayersRecursive(sublayers[i].get(), TransformationMatrix(), matrix, surfaceLayers, opacity, clipRect); 314 } 315 316 // Decompose the dirty rect into a set of non-overlaping rectangles 317 // (they need to not overlap so that the blending code doesn't draw any region twice). 318 for (int i = 0; i < LayerRenderingResults::NumberOfDirtyRects; ++i) { 319 BlackBerry::Platform::IntRectRegion region(BlackBerry::Platform::IntRect(m_lastRenderingResults.dirtyRect(i))); 320 m_lastRenderingResults.dirtyRegion = BlackBerry::Platform::IntRectRegion::unionRegions(m_lastRenderingResults.dirtyRegion, region); 321 } 322 323 // If we won't draw anything, don't touch the OpenGL APIs. 324 if (m_lastRenderingResults.isEmpty() && m_lastRenderingResults.wasEmpty) 325 return; 326 327 // Okay, we're going to do some drawing. 328 if (!makeContextCurrent()) 329 return; 330 331 // If some layers should be drawn on temporary surfaces, we should do it first. 332 if (!surfaceLayers.isEmpty()) 333 drawLayersOnSurfaces(surfaceLayers); 334 335 // Don't render the root layer, the BlackBerry port uses the BackingStore to draw the 336 // root layer. 337 for (size_t i = 0; i < sublayers.size(); i++) { 338 int currentStencilValue = 0; 339 FloatRect clipRect(m_clipRect); 340 compositeLayersRecursive(sublayers[i].get(), currentStencilValue, clipRect); 341 } 342 343 // We need to make sure that all texture resource usage is finished before 344 // unlocking the texture resources, so force a glFinish() in that case. 345 if (m_layersLockingTextureResources.size()) 346 glFinish(); 347 348 m_client->context()->swapBuffers(); 349 350 glDisable(GL_SCISSOR_TEST); 351 glDisable(GL_STENCIL_TEST); 352 353 // PR 147254, the EGL implementation crashes when the last bound texture 354 // was an EGLImage, and you try to bind another texture and the pixmap 355 // backing the EGLImage was deleted in between. Make this easier for the 356 // driver by unbinding early (when the pixmap is hopefully still around). 357 glBindTexture(GL_TEXTURE_2D, 0); 358 359 LayerSet::iterator iter = m_layersLockingTextureResources.begin(); 360 for (; iter != m_layersLockingTextureResources.end(); ++iter) 361 (*iter)->releaseTextureResources(); 362 363 m_layersLockingTextureResources.clear(); 364 365 if (m_needsCommit) { 366 m_needsCommit = false; 367 rootLayer->scheduleCommit(); 368 } 369 370 textureCacheCompositingThread()->collectGarbage(); 371} 372 373static float texcoords[4 * 2] = { 0, 0, 1, 0, 1, 1, 0, 1 }; 374 375void LayerRenderer::compositeBuffer(const TransformationMatrix& transform, const FloatRect& contents, BlackBerry::Platform::Graphics::Buffer* buffer, bool contentsOpaque, float opacity) 376{ 377 if (!buffer) 378 return; 379 380 FloatQuad vertices(transform.mapPoint(contents.minXMinYCorner()), 381 transform.mapPoint(contents.minXMaxYCorner()), 382 transform.mapPoint(contents.maxXMaxYCorner()), 383 transform.mapPoint(contents.maxXMinYCorner())); 384 385 if (!vertices.boundingBox().intersects(m_clipRect)) 386 return; 387 388 if (!contentsOpaque || opacity < 1.0f) { 389 glEnable(GL_BLEND); 390 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 391 } else 392 glDisable(GL_BLEND); 393 394 if (BlackBerry::Platform::Graphics::lockAndBindBufferGLTexture(buffer, GL_TEXTURE_2D)) { 395 const GLES2Program& program = useProgram(LayerProgramRGBA); 396 glUniform1f(program.opacityLocation(), opacity); 397 398 glVertexAttribPointer(program.positionLocation(), 2, GL_FLOAT, GL_FALSE, 0, &vertices); 399 glVertexAttribPointer(program.texCoordLocation(), 2, GL_FLOAT, GL_FALSE, 0, texcoords); 400 401 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 402 BlackBerry::Platform::Graphics::releaseBufferGLTexture(buffer); 403 } 404} 405 406void LayerRenderer::drawColor(const TransformationMatrix& transform, const FloatRect& contents, const Color& color) 407{ 408 FloatQuad vertices(transform.mapPoint(contents.minXMinYCorner()), 409 transform.mapPoint(contents.minXMaxYCorner()), 410 transform.mapPoint(contents.maxXMaxYCorner()), 411 transform.mapPoint(contents.maxXMinYCorner())); 412 413 if (!vertices.boundingBox().intersects(m_clipRect)) 414 return; 415 416 const GLES2Program& program = useProgram(ColorProgram); 417 418 if (color.alpha() < 255) { 419 glEnable(GL_BLEND); 420 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 421 } else 422 glDisable(GL_BLEND); 423 424 glUniform4f(m_colorColorLocation, color.red() / 255.0, color.green() / 255.0, color.blue() / 255.0, color.alpha() / 255.0); 425 glVertexAttribPointer(program.positionLocation(), 2, GL_FLOAT, GL_FALSE, 0, &vertices); 426 427 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 428} 429 430bool LayerRenderer::useSurface(LayerRendererSurface* surface) 431{ 432 if (m_currentLayerRendererSurface == surface) 433 return true; 434 435 m_currentLayerRendererSurface = surface; 436 if (!surface) { 437 glBindFramebuffer(GL_FRAMEBUFFER, 0); 438 glViewport(m_viewport.x(), m_viewport.y(), m_viewport.width(), m_viewport.height()); 439 return true; 440 } 441 442 surface->ensureTexture(); 443 444 GLuint texid = surface->texture()->platformTexture(); 445 446 if (!m_fbo) 447 glGenFramebuffers(1, &m_fbo); 448 glBindTexture(GL_TEXTURE_2D, 0); 449 glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); 450 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texid, 0); 451 452#ifndef NDEBUG 453 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); 454 if (status != GL_FRAMEBUFFER_COMPLETE) { 455 fprintf(stderr, "glCheckFramebufferStatus error %x\n", status); 456 return false; 457 } 458#endif 459 460 glViewport(0, 0, surface->size().width(), surface->size().height()); 461 return true; 462} 463 464void LayerRenderer::drawLayersOnSurfaces(const Vector<RefPtr<LayerCompositingThread> >& surfaceLayers) 465{ 466 // Normally, an upside-down transform is used, as is the GL custom. However, when drawing 467 // layers to surfaces, a right-side-up transform is used, so we need to switch the winding order 468 // for culling. 469 glFrontFace(GL_CCW); 470 471 for (int i = surfaceLayers.size() - 1; i >= 0; i--) { 472 LayerCompositingThread* layer = surfaceLayers[i].get(); 473 LayerRendererSurface* surface = layer->layerRendererSurface(); 474 if (!surface || !useSurface(surface)) 475 continue; 476 477 glDisable(GL_SCISSOR_TEST); 478 glClearColor(0, 0, 0, 0); 479 glClear(GL_COLOR_BUFFER_BIT); 480 481 int currentStencilValue = 0; 482 FloatRect clipRect(-1, -1, 2, 2); 483 compositeLayersRecursive(surfaceLayers[i].get(), currentStencilValue, clipRect); 484 485#if ENABLE(CSS_FILTERS) 486 if (!m_filterRenderer) 487 m_filterRenderer = LayerFilterRenderer::create(GLES2Program::PositionAttributeIndex, GLES2Program::TexCoordAttributeIndex); 488 if (layer->filterOperationsChanged()) { 489 layer->setFilterOperationsChanged(false); 490 layer->setFilterActions(m_filterRenderer->actionsForOperations(surface, layer->filters().operations())); 491 } 492 m_filterRenderer->applyActions(m_fbo, layer, layer->filterActions()); 493 glClearColor(0, 0, 0, 0); 494#endif 495 } 496 497 glFrontFace(GL_CW); 498 499 // If there are layers drawn on surfaces, we need to switch to default framebuffer. 500 // Otherwise, we just need to set viewport. 501 useSurface(0); 502 glEnable(GL_SCISSOR_TEST); 503 glScissor(m_scissorRect.x(), m_scissorRect.y(), m_scissorRect.width(), m_scissorRect.height()); 504} 505 506void LayerRenderer::addLayer(LayerCompositingThread* layer) 507{ 508 m_layers.add(layer); 509} 510 511bool LayerRenderer::removeLayer(LayerCompositingThread* layer) 512{ 513 LayerSet::iterator iter = m_layers.find(layer); 514 if (iter == m_layers.end()) 515 return false; 516 m_layers.remove(layer); 517 return true; 518} 519 520void LayerRenderer::addLayerToReleaseTextureResourcesList(LayerCompositingThread* layer) 521{ 522 m_layersLockingTextureResources.add(layer); 523} 524 525static int glRound(float f) 526{ 527 return floorf(f + 0.5f); 528} 529 530// Transform normalized device coordinates to window coordinates 531// as specified in the OpenGL ES 2.0 spec section 2.12.1. 532IntRect LayerRenderer::toOpenGLWindowCoordinates(const FloatRect& r) const 533{ 534 float vw2 = m_viewport.width() / 2.0; 535 float vh2 = m_viewport.height() / 2.0; 536 float ox = m_viewport.x() + vw2; 537 float oy = m_viewport.y() + vh2; 538 return IntRect(glRound(r.x() * vw2 + ox), glRound(r.y() * vh2 + oy), glRound(r.width() * vw2), glRound(r.height() * vh2)); 539} 540 541static FloatRect toPixelCoordinates(const FloatRect& rect, const IntRect& viewport, int surfaceHeight) 542{ 543 float vw2 = viewport.width() / 2.0; 544 float vh2 = viewport.height() / 2.0; 545 float ox = viewport.x() + vw2; 546 float oy = surfaceHeight - (viewport.y() + vh2); 547 return FloatRect(rect.x() * vw2 + ox, -(rect.y() + rect.height()) * vh2 + oy, rect.width() * vw2, rect.height() * vh2); 548} 549 550// Transform normalized device coordinates to window coordinates as WebKit understands them. 551// 552// The OpenGL surface may be larger than the WebKit window, and OpenGL window coordinates 553// have origin in bottom left while WebKit window coordinates origin is in top left. 554// The viewport is setup to cover the upper portion of the larger OpenGL surface. 555IntRect LayerRenderer::toWindowCoordinates(const FloatRect& rect) const 556{ 557 return enclosingIntRect(toPixelCoordinates(rect, m_viewport, m_client->context()->surfaceSize().height())); 558} 559 560IntRect LayerRenderer::toPixelViewportCoordinates(const FloatRect& rect) const 561{ 562 // The clip rect defines the web page's pixel viewport (to use ViewportAccessor terminology), 563 // not to be confused with the GL viewport. So translate from window coordinates to pixel 564 // viewport coordinates. 565 int surfaceHeight = m_client->context()->surfaceSize().height(); 566 FloatRect pixelViewport = toPixelCoordinates(m_clipRect, m_viewport, surfaceHeight); 567 FloatRect result = toPixelCoordinates(rect, m_viewport, surfaceHeight); 568 result.move(-pixelViewport.x(), -pixelViewport.y()); 569 return enclosingIntRect(result); 570} 571 572IntRect LayerRenderer::toDocumentViewportCoordinates(const FloatRect& rect) const 573{ 574 // Similar to toPixelViewportCoordinates except that this also takes any zoom into account. 575 FloatRect result = toPixelViewportCoordinates(rect); 576 result.scale(1 / m_scale); 577 return enclosingIntRect(result); 578} 579 580void LayerRenderer::drawDebugBorder(const Vector<FloatPoint>& transformedBounds, const Color& borderColor, float borderWidth) 581{ 582 if (borderColor.alpha() < 255) { 583 glEnable(GL_BLEND); 584 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 585 } else 586 glDisable(GL_BLEND); 587 588 const GLES2Program& program = useProgram(ColorProgram); 589 glVertexAttribPointer(program.positionLocation(), 2, GL_FLOAT, GL_FALSE, 0, transformedBounds.data()); 590 glUniform4f(m_colorColorLocation, borderColor.red() / 255.0, borderColor.green() / 255.0, borderColor.blue() / 255.0, borderColor.alpha() / 255.0); 591 592 glLineWidth(borderWidth); 593 glDrawArrays(GL_LINE_LOOP, 0, transformedBounds.size()); 594} 595 596// Draws a debug border around the layer's bounds. 597void LayerRenderer::drawDebugBorder(LayerCompositingThread* layer) 598{ 599 Color borderColor = layer->borderColor(); 600 601#if DEBUG_LAYER_ANIMATIONS 602 if (layer->hasRunningAnimations()) 603 borderColor = Color(0x00, 0xFF, 0x00, 0xFF); 604#endif 605 606 if (!borderColor.alpha()) 607 return; 608 609 // If we're rendering to a surface, don't include debug border inside the surface. 610 if (m_currentLayerRendererSurface) 611 return; 612 613 Vector<FloatPoint> transformedBounds; 614 if (layerAlreadyOnSurface(layer)) 615 transformedBounds = layer->layerRendererSurface()->transformedBounds(); 616 else 617 transformedBounds = layer->transformedBounds(); 618 619 drawDebugBorder(transformedBounds, borderColor, std::max(1.0f, layer->borderWidth())); 620} 621 622// Clears a rectangle inside the layer's bounds. 623void LayerRenderer::drawHolePunchRect(LayerCompositingThread* layer) 624{ 625 const GLES2Program& program = useProgram(ColorProgram); 626 glUniform4f(m_colorColorLocation, 0, 0, 0, 0); 627 628 glEnable(GL_BLEND); 629 glBlendFunc(GL_ONE, GL_ZERO); 630 FloatQuad hole = layer->transformedHolePunchRect(); 631 glVertexAttribPointer(program.positionLocation(), 2, GL_FLOAT, GL_FALSE, 0, &hole); 632 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 633 checkGLError(); 634} 635 636void LayerRenderer::prepareFrameRecursive(LayerCompositingThread* layer, double animationTime, bool isContextCurrent) 637{ 638 // This might cause the layer to recompute some attributes. 639 m_lastRenderingResults.needsAnimationFrame |= layer->updateAnimations(animationTime); 640 641 if (isContextCurrent) { 642 // Even non-visible layers need to perform their texture jobs, or they will 643 // pile up and waste memory. 644 if (layer->needsTexture()) 645 layer->updateTextureContentsIfNeeded(); 646 if (layer->maskLayer() && layer->maskLayer()->needsTexture()) 647 layer->maskLayer()->updateTextureContentsIfNeeded(); 648 if (layer->replicaLayer()) { 649 LayerCompositingThread* replica = layer->replicaLayer(); 650 if (replica->needsTexture()) 651 replica->updateTextureContentsIfNeeded(); 652 if (replica->maskLayer() && replica->maskLayer()->needsTexture()) 653 replica->maskLayer()->updateTextureContentsIfNeeded(); 654 } 655 } 656 657 const Vector<RefPtr<LayerCompositingThread> >& sublayers = layer->sublayers(); 658 for (size_t i = 0; i < sublayers.size(); i++) 659 prepareFrameRecursive(sublayers[i].get(), animationTime, isContextCurrent); 660} 661 662void LayerRenderer::updateLayersRecursive(LayerCompositingThread* layer, const TransformationMatrix& matrix, const TransformationMatrix& projectionMatrix, Vector<RefPtr<LayerCompositingThread> >& surfaceLayers, float opacity, FloatRect clipRect) 663{ 664 // The contract for LayerCompositingThread::setLayerRenderer is it must be set if the layer has been rendered. 665 // So do it now, before we render it in compositeLayersRecursive. 666 layer->setLayerRenderer(this); 667 if (layer->maskLayer()) 668 layer->maskLayer()->setLayerRenderer(this); 669 if (layer->replicaLayer()) { 670 LayerCompositingThread* replica = layer->replicaLayer(); 671 replica->setLayerRenderer(this); 672 if (replica->maskLayer()) 673 replica->maskLayer()->setLayerRenderer(this); 674 } 675 676 // Compute the new matrix transformation that will be applied to this layer and 677 // all its sublayers. It's important to remember that the layer's position 678 // is the position of the layer's anchor point. Also, the coordinate system used 679 // assumes that the origin is at the lower left even though the coordinates the browser 680 // gives us for the layers are for the upper left corner. The Y flip happens via 681 // the orthographic projection applied at render time. 682 // The transformation chain for the layer is (using the Matrix x Vector order): 683 // M = M[p] * Tr[l] * M[l] * Tr[c] 684 // Where M[p] is the parent matrix passed down to the function 685 // Tr[l] is the translation matrix locating the layer's anchor point 686 // Tr[c] is the translation offset between the anchor point and the center of the layer 687 // M[l] is the layer's matrix (applied at the anchor point) 688 // This transform creates a coordinate system whose origin is the center of the layer. 689 // Note that the final matrix used by the shader for the layer is P * M * S . This final product 690 // is computed in drawTexturedQuad(). 691 // Where: P is the projection matrix 692 // M is the layer's matrix computed above 693 // S is the scale adjustment (to scale up to the layer size) 694 FloatSize bounds = layer->bounds(); 695 if (layer->sizeIsScaleInvariant()) 696 bounds.scale(1.0 / m_scale); 697 FloatPoint anchorPoint = layer->anchorPoint(); 698 FloatPoint position = layer->position(); 699 700 // Layer whose hasFixedContainer is true will get scrolled relative to 701 // the fixed positioned parent. 702 if (!layer->hasFixedContainer() && (layer->isFixedPosition() || layer->hasFixedAncestorInDOMTree())) { 703 FloatRect layoutRect = m_layoutRect; 704 FloatSize contentsSize = m_contentsSize; 705 FloatRect visibleRect = m_visibleRect; 706 for (LayerCompositingThread* curr = layer->superlayer(); curr; curr = curr->superlayer()) { 707 708 if (curr->isContainerForFixedPositionLayers()) { 709 layoutRect = curr->frameVisibleRect(); 710 contentsSize = curr->frameContentsSize(); 711 712 // If we reach a container for fixed position layers, and it has its override's position set, it means it is a scrollable iframe 713 // currently being scrolled. Otherwise, use the WebKit-thread scroll position stored in frameVisibleRect(). 714 if (curr->override()->isPositionSet()) { 715 // Inverted logic of 716 // FloatPoint layerPosition(-scrollPosition.x() + anchor.x() * bounds.width(), 717 // -scrollPosition.y() + anchor.y() * bounds.height()); 718 FloatPoint scrollPosition( 719 -(curr->override()->position().x() - (curr->anchorPoint().x() * curr->bounds().width())), 720 -(curr->override()->position().y() - (curr->anchorPoint().y() * curr->bounds().height()))); 721 visibleRect = FloatRect(scrollPosition, layoutRect.size()); 722 } else 723 visibleRect = layoutRect; 724 725 break; 726 } 727 } 728 729 FloatPoint maximumScrollPosition = FloatPoint(0, 0) + (contentsSize - visibleRect.size()); 730 FloatPoint maximumLayoutScrollPosition = FloatPoint(0, 0) + (contentsSize - layoutRect.size()); 731 732 // The basic idea here is to set visible x/y to the value we want, and 733 // layout x/y to the value WebCore layouted the fixed element to. 734 float visibleY; 735 float layoutY; 736 if (layer->isFixedToTop()) { 737 visibleY = max(0.0f, min(maximumScrollPosition.y(), visibleRect.y())); 738 layoutY = max(0.0f, min(maximumLayoutScrollPosition.y(), layoutRect.y())); 739 } else { 740 visibleY = min(contentsSize.height(), visibleRect.y() + visibleRect.height()); 741 layoutY = min(contentsSize.height(), max(0.0f, layoutRect.y()) + layoutRect.height()); 742 } 743 position.setY(position.y() + (visibleY - layoutY)); 744 745 float visibleX; 746 float layoutX; 747 if (layer->isFixedToLeft()) { 748 visibleX = max(0.0f, min(maximumScrollPosition.x(), visibleRect.x())); 749 layoutX = max(0.0f, min(maximumLayoutScrollPosition.x(), layoutRect.x())); 750 } else { 751 visibleX = min(contentsSize.width(), visibleRect.x() + visibleRect.width()); 752 layoutX = min(contentsSize.width(), max(0.0f, layoutRect.x()) + layoutRect.width()); 753 } 754 position.setX(position.x() + (visibleX - layoutX)); 755 } 756 757 // Offset between anchor point and the center of the quad. 758 float centerOffsetX = (0.5 - anchorPoint.x()) * bounds.width(); 759 float centerOffsetY = (0.5 - anchorPoint.y()) * bounds.height(); 760 761 // M = M[p] 762 TransformationMatrix localMatrix = matrix; 763 // M = M[p] * Tr[l] 764 localMatrix.translate3d(position.x(), position.y(), layer->anchorPointZ()); 765 // M = M[p] * Tr[l] * M[l] 766 localMatrix.multiply(layer->transform()); 767 // M = M[p] * Tr[l] * M[l] * Tr[c] 768 localMatrix.translate3d(centerOffsetX, centerOffsetY, -layer->anchorPointZ()); 769 770 // Calculate the layer's opacity. 771 opacity *= layer->opacity(); 772 773 TransformationMatrix localProjectionMatrix = projectionMatrix; 774#if ENABLE(CSS_FILTERS) 775 bool useLayerRendererSurface = layer->maskLayer() || layer->replicaLayer() || layer->filters().size(); 776#else 777 bool useLayerRendererSurface = layer->maskLayer() || layer->replicaLayer(); 778#endif 779 if (!useLayerRendererSurface) { 780 layer->setDrawOpacity(opacity); 781 layer->clearLayerRendererSurface(); 782 } else { 783 if (!layer->layerRendererSurface()) 784 layer->createLayerRendererSurface(); 785 786 LayerRendererSurface* surface = layer->layerRendererSurface(); 787 788 layer->setDrawOpacity(1.0); 789 surface->setDrawOpacity(opacity); 790 791 surface->setDrawTransform(localMatrix, projectionMatrix); 792 if (layer->replicaLayer()) { 793 TransformationMatrix replicaMatrix = localMatrix; 794 replicaMatrix.translate3d(-0.5 * bounds.width(), -0.5 * bounds.height(), 0); 795 replicaMatrix.translate3d(layer->replicaLayer()->position().x(), layer->replicaLayer()->position().y(), 0); 796 replicaMatrix.multiply(layer->replicaLayer()->transform()); 797 replicaMatrix.translate3d(centerOffsetX, centerOffsetY, 0); 798 surface->setReplicaDrawTransform(replicaMatrix, projectionMatrix); 799 } 800 801 IntRect contentRect = enclosingIntRect(FloatRect(FloatPoint::zero(), bounds)); 802 surface->setContentRect(contentRect); 803 804 localProjectionMatrix = orthoMatrix(contentRect.x(), contentRect.maxX(), contentRect.y(), contentRect.maxY(), -1000, 1000); 805 // The origin of the new surface is the upper left corner of the layer. 806 TransformationMatrix drawTransform; 807 drawTransform.translate3d(0.5 * bounds.width(), 0.5 * bounds.height(), 0); 808 // This layer will start using new transformation. 809 localMatrix = drawTransform; 810 811 surfaceLayers.append(layer); 812 } 813 814 layer->setDrawTransform(m_scale, localMatrix, localProjectionMatrix); 815 816#if ENABLE(VIDEO) 817 bool layerVisible = clipRect.intersects(layer->boundingBox()) || layer->mediaPlayer(); 818#else 819 bool layerVisible = clipRect.intersects(layer->boundingBox()); 820#endif 821 822 if (layer->needsTexture() && layerVisible) { 823 IntRect dirtyRect = toWindowCoordinates(intersection(layer->boundingBox(), clipRect)); 824 m_lastRenderingResults.addDirtyRect(dirtyRect); 825 } 826 827 if (layer->masksToBounds()) 828 clipRect.intersect(layer->boundingBox()); 829 830 // Flatten to 2D if the layer doesn't preserve 3D. 831 if (!layer->preserves3D()) { 832 localMatrix.setM13(0); 833 localMatrix.setM23(0); 834 localMatrix.setM31(0); 835 localMatrix.setM32(0); 836 localMatrix.setM33(1); 837 localMatrix.setM34(0); 838 localMatrix.setM43(0); 839 } 840 841 // Apply the sublayer transform. 842 localMatrix.multiply(layer->sublayerTransform()); 843 844 // The origin of the sublayers is actually the bottom left corner of the layer 845 // (or top left when looking it it from the browser's pespective) instead of the center. 846 // The matrix passed down to the sublayers is therefore: 847 // M[s] = M * Tr[-center] 848 localMatrix.translate3d(-bounds.width() * 0.5, -bounds.height() * 0.5, 0); 849 850 const Vector<RefPtr<LayerCompositingThread> >& sublayers = layer->sublayers(); 851 for (size_t i = 0; i < sublayers.size(); i++) 852 updateLayersRecursive(sublayers[i].get(), localMatrix, localProjectionMatrix, surfaceLayers, opacity, clipRect); 853} 854 855static bool hasRotationalComponent(const TransformationMatrix& m) 856{ 857 return m.m12() || m.m13() || m.m23() || m.m21() || m.m31() || m.m32(); 858} 859 860bool LayerRenderer::layerAlreadyOnSurface(LayerCompositingThread* layer) const 861{ 862 return layer->layerRendererSurface() && layer->layerRendererSurface() != m_currentLayerRendererSurface; 863} 864 865static void collect3DPreservingLayers(Vector<LayerCompositingThread*>& layers) 866{ 867 for (size_t i = 0; i < layers.size(); ++i) { 868 LayerCompositingThread* layer = layers[i]; 869 if (!layer->preserves3D() || !layer->sublayers().size()) 870 continue; 871 872 Vector<LayerCompositingThread*> sublayers = rawPtrVectorFromRefPtrVector(layer->sublayers()); 873 collect3DPreservingLayers(sublayers); 874 layers.insert(i+1, sublayers); 875 i += sublayers.size(); 876 } 877} 878 879void LayerRenderer::compositeLayersRecursive(LayerCompositingThread* layer, int stencilValue, FloatRect clipRect) 880{ 881 FloatRect rect; 882 if (layerAlreadyOnSurface(layer)) 883 rect = layer->layerRendererSurface()->boundingBox(); 884 else 885 rect = layer->boundingBox(); 886 887#if ENABLE(VIDEO) 888 bool layerVisible = clipRect.intersects(rect) || layer->mediaPlayer(); 889#else 890 bool layerVisible = clipRect.intersects(rect); 891#endif 892 893 layer->setVisible(layerVisible); 894 895 // Note that there are two types of layers: 896 // 1. Layers that have their own GraphicsContext and can draw their contents on demand (layer->drawsContent() == true). 897 // 2. Layers that are just containers of images/video/etc that don't own a GraphicsContext (layer->contents() == true). 898 899 if ((layer->needsTexture() || layer->layerRendererSurface()) && layerVisible) { 900 updateScissorIfNeeded(clipRect); 901 902 if (stencilValue) { 903 glStencilFunc(GL_EQUAL, stencilValue, 0xff); 904 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); 905 } 906 907 if (layer->doubleSided()) 908 glDisable(GL_CULL_FACE); 909 else 910 glEnable(GL_CULL_FACE); 911 912 if (layer->hasVisibleHolePunchRect()) 913 drawHolePunchRect(layer); 914 915 // Draw the surface onto another surface or screen. 916 bool drawSurface = layerAlreadyOnSurface(layer); 917 // The texture format for the surface is RGBA. 918 LayerData::LayerProgram layerProgram = drawSurface ? LayerData::LayerProgramRGBA : layer->layerProgram(); 919 920 if (!drawSurface) { 921 const GLES2Program& program = useLayerProgram(layerProgram); 922 layer->drawTextures(program, m_scale, m_visibleRect, clipRect); 923 } else { 924 // Draw the reflection if it exists. 925 if (layer->replicaLayer()) { 926 // If this layer and its reflection both have mask, we need another temporary surface. 927 // Since this use case should be rare, currently it's not handled and the mask for 928 // the reflection is applied only when this layer has no mask. 929 LayerCompositingThread* mask = layer->maskLayer(); 930 if (!mask && layer->replicaLayer()) 931 mask = layer->replicaLayer()->maskLayer(); 932 933 const GLES2Program& program = useLayerProgram(layerProgram, mask); 934 layer->drawSurface(program, layer->layerRendererSurface()->replicaDrawTransform(), mask); 935 } 936 937 const GLES2Program& program = useLayerProgram(layerProgram, layer->maskLayer()); 938 layer->drawSurface(program, layer->layerRendererSurface()->drawTransform(), layer->maskLayer()); 939 } 940 } 941 942 // Draw the debug border if there is one. 943 drawDebugBorder(layer); 944 945 // The texture for the LayerRendererSurface can be released after the surface was drawn on another surface. 946 if (layerAlreadyOnSurface(layer)) { 947 layer->layerRendererSurface()->releaseTexture(); 948 return; 949 } 950 951 // If we need to mask to bounds but the transformation has a rotational component 952 // to it, scissoring is not enough and we need to use the stencil buffer for clipping. 953 bool stencilClip = layer->masksToBounds() && hasRotationalComponent(layer->drawTransform()); 954 955 if (stencilClip) { 956 if (!m_stencilCleared) { 957 glStencilMask(0xffffffff); 958 glClearStencil(0); 959 glClear(GL_STENCIL_BUFFER_BIT); 960 m_stencilCleared = true; 961 } 962 963 glEnable(GL_STENCIL_TEST); 964 glStencilFunc(GL_EQUAL, stencilValue, 0xff); 965 glStencilOp(GL_KEEP, GL_INCR, GL_INCR); 966 967 updateScissorIfNeeded(clipRect); 968 const GLES2Program& program = useProgram(ColorProgram); 969 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); 970 glVertexAttribPointer(program.positionLocation(), 2, GL_FLOAT, GL_FALSE, 0, layer->transformedBounds().data()); 971 glDrawArrays(GL_TRIANGLE_FAN, 0, layer->transformedBounds().size()); 972 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 973 } 974 975 if (layer->masksToBounds()) 976 clipRect.intersect(layer->boundingBox()); 977 978 // Here, we need to sort the whole subtree of layers with preserve-3d. It 979 // affects all children, and the children of any children with preserve-3d, 980 // and so on. 981 Vector<LayerCompositingThread*> sublayers = rawPtrVectorFromRefPtrVector(layer->sublayers()); 982 983 bool preserves3D = layer->preserves3D(); 984 bool superlayerPreserves3D = layer->superlayer() && layer->superlayer()->preserves3D(); 985 986 // Collect and render all sublayers with preserves-3D. 987 // If the superlayer preserves 3D, we've already collected and rendered its 988 // children, so bail. 989 if (preserves3D && !superlayerPreserves3D) { 990 collect3DPreservingLayers(sublayers); 991 std::stable_sort(sublayers.begin(), sublayers.end(), compareLayerW); 992 } 993 994 int newStencilValue = stencilClip ? stencilValue+1 : stencilValue; 995 for (size_t i = 0; i < sublayers.size(); i++) { 996 LayerCompositingThread* sublayer = sublayers[i]; 997 // The root of the 3d-preserving subtree has collected all 998 // 3d-preserving layers and their children and will render them all in 999 // the right order. 1000 if (preserves3D && superlayerPreserves3D) 1001 continue; 1002 1003 compositeLayersRecursive(sublayer, newStencilValue, clipRect); 1004 } 1005 1006 if (stencilClip) { 1007 glStencilFunc(GL_LEQUAL, stencilValue, 0xff); 1008 glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); 1009 1010 updateScissorIfNeeded(clipRect); 1011 const GLES2Program& program = useProgram(ColorProgram); 1012 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); 1013 glVertexAttribPointer(program.positionLocation(), 2, GL_FLOAT, GL_FALSE, 0, layer->transformedBounds().data()); 1014 glDrawArrays(GL_TRIANGLE_FAN, 0, layer->transformedBounds().size()); 1015 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 1016 1017 if (!stencilValue) 1018 glDisable(GL_STENCIL_TEST); 1019 } 1020} 1021 1022void LayerRenderer::updateScissorIfNeeded(const FloatRect& clipRect) 1023{ 1024#if DEBUG_CLIPPING 1025 printf("LayerRenderer::updateScissorIfNeeded(): clipRect=(%.2f,%.2f %.2fx%.2f)\n", clipRect.x(), clipRect.y(), clipRect.width(), clipRect.height()); 1026 fflush(stdout); 1027#endif 1028 IntRect clipRectWC = toOpenGLWindowCoordinates(clipRect); 1029 if (m_scissorRect == clipRectWC) 1030 return; 1031 1032 m_scissorRect = clipRectWC; 1033#if DEBUG_CLIPPING 1034 printf("LayerRenderer::updateScissorIfNeeded(): clipping to (%d,%d %dx%d)\n", m_scissorRect.x(), m_scissorRect.y(), m_scissorRect.width(), m_scissorRect.height()); 1035 fflush(stdout); 1036#endif 1037 glScissor(m_scissorRect.x(), m_scissorRect.y(), m_scissorRect.width(), m_scissorRect.height()); 1038} 1039 1040bool LayerRenderer::makeContextCurrent() 1041{ 1042 bool ret = m_client->context()->makeCurrent(); 1043 if (ret && m_isRobustnessSupported) { 1044 if (m_glGetGraphicsResetStatusEXT() != GL_NO_ERROR) { 1045 BlackBerry::Platform::logAlways(BlackBerry::Platform::LogLevelCritical, "Robust OpenGL context has been reset. Aborting."); 1046 CRASH(); 1047 } 1048 } 1049 return ret; 1050} 1051 1052bool LayerRenderer::createProgram(ProgramIndex program) 1053{ 1054 // Shaders for drawing the layer contents. 1055 const char* vertexShaderString = 1056 "attribute vec4 a_position; \n" 1057 "attribute vec2 a_texCoord; \n" 1058 "varying vec2 v_texCoord; \n" 1059 "void main() \n" 1060 "{ \n" 1061 " gl_Position = a_position; \n" 1062 " v_texCoord = a_texCoord; \n" 1063 "} \n"; 1064 1065 const char* fragmentShaderStringRGBA = 1066 "varying mediump vec2 v_texCoord; \n" 1067 "uniform lowp sampler2D s_texture; \n" 1068 "uniform lowp float alpha; \n" 1069 "void main() \n" 1070 "{ \n" 1071 " gl_FragColor = texture2D(s_texture, v_texCoord) * alpha; \n" 1072 "} \n"; 1073 1074 const char* fragmentShaderStringBGRA = 1075 "varying mediump vec2 v_texCoord; \n" 1076 "uniform lowp sampler2D s_texture; \n" 1077 "uniform lowp float alpha; \n" 1078 "void main() \n" 1079 "{ \n" 1080 " gl_FragColor = texture2D(s_texture, v_texCoord).bgra * alpha; \n" 1081 "} \n"; 1082 1083 const char* fragmentShaderStringMaskRGBA = 1084 "varying mediump vec2 v_texCoord; \n" 1085 "uniform lowp sampler2D s_texture; \n" 1086 "uniform lowp sampler2D s_mask; \n" 1087 "uniform lowp float alpha; \n" 1088 "void main() \n" 1089 "{ \n" 1090 " lowp vec4 texColor = texture2D(s_texture, v_texCoord); \n" 1091 " lowp vec4 maskColor = texture2D(s_mask, v_texCoord); \n" 1092 " gl_FragColor = vec4(texColor.x, texColor.y, texColor.z, texColor.w) * alpha * maskColor.w; \n" 1093 "} \n"; 1094 1095 const char* fragmentShaderStringMaskBGRA = 1096 "varying mediump vec2 v_texCoord; \n" 1097 "uniform lowp sampler2D s_texture; \n" 1098 "uniform lowp sampler2D s_mask; \n" 1099 "uniform lowp float alpha; \n" 1100 "void main() \n" 1101 "{ \n" 1102 " lowp vec4 texColor = texture2D(s_texture, v_texCoord).bgra; \n" 1103 " lowp vec4 maskColor = texture2D(s_mask, v_texCoord).bgra; \n" 1104 " gl_FragColor = vec4(texColor.x, texColor.y, texColor.z, texColor.w) * alpha * maskColor.w; \n" 1105 "} \n"; 1106 1107 // Shaders for drawing the debug borders around the layers. 1108 const char* colorVertexShaderString = 1109 "attribute vec4 a_position; \n" 1110 "void main() \n" 1111 "{ \n" 1112 " gl_Position = a_position; \n" 1113 "} \n"; 1114 1115 const char* colorFragmentShaderString = 1116 "uniform lowp vec4 color; \n" 1117 "void main() \n" 1118 "{ \n" 1119 " gl_FragColor = color; \n" 1120 "} \n"; 1121 1122 const char* vertexShader = 0; 1123 const char* fragmentShader = 0; 1124 1125 switch (program) { 1126 case LayerProgramRGBA: 1127 case LayerProgramBGRA: 1128 case LayerMaskProgramRGBA: 1129 case LayerMaskProgramBGRA: 1130 vertexShader = vertexShaderString; 1131 break; 1132 case ColorProgram: 1133 vertexShader = colorVertexShaderString; 1134 break; 1135 case NumberOfPrograms: 1136 return false; 1137 } 1138 1139 switch (program) { 1140 case LayerProgramRGBA: 1141 fragmentShader = fragmentShaderStringRGBA; 1142 break; 1143 case LayerProgramBGRA: 1144 fragmentShader = fragmentShaderStringBGRA; 1145 break; 1146 case LayerMaskProgramRGBA: 1147 fragmentShader = fragmentShaderStringMaskRGBA; 1148 break; 1149 case LayerMaskProgramBGRA: 1150 fragmentShader = fragmentShaderStringMaskBGRA; 1151 break; 1152 case ColorProgram: 1153 fragmentShader = colorFragmentShaderString; 1154 break; 1155 case NumberOfPrograms: 1156 return false; 1157 } 1158 1159 if (!vertexShader || !fragmentShader) 1160 return false; 1161 1162 GLuint programObject = loadShaderProgram(vertexShader, fragmentShader); 1163 if (!programObject) { 1164 LOG_ERROR("Failed to create program %u", program); 1165 return false; 1166 } 1167 1168 m_programs[program].m_program = programObject; 1169 1170 // Binds the given attribute name to a common location across all programs 1171 // used by the compositor. This allows the code to bind the attributes only once 1172 // even when switching between programs. 1173 glBindAttribLocation(programObject, GLES2Program::PositionAttributeIndex, "a_position"); 1174 glBindAttribLocation(programObject, GLES2Program::TexCoordAttributeIndex, "a_texCoord"); 1175 1176 checkGLError(); 1177 1178 // Re-link the shader to get the new attrib location to take effect. 1179 glLinkProgram(programObject); 1180 1181 checkGLError(); 1182 1183 // Get locations of uniforms for the layer content shader program. 1184 m_programs[program].m_locations[GLES2Program::OpacityUniform] = glGetUniformLocation(programObject, "alpha"); 1185 switch (program) { 1186 case LayerProgramRGBA: 1187 case LayerProgramBGRA: { 1188 GLint samplerLocation = glGetUniformLocation(programObject, "s_texture"); 1189 glUseProgram(programObject); 1190 glUniform1i(samplerLocation, 0); 1191 break; 1192 } 1193 case LayerMaskProgramRGBA: 1194 case LayerMaskProgramBGRA: { 1195 GLint maskSamplerLocation = glGetUniformLocation(programObject, "s_texture"); 1196 GLint maskSamplerLocationMask = glGetUniformLocation(programObject, "s_mask"); 1197 glUseProgram(programObject); 1198 glUniform1i(maskSamplerLocation, 0); 1199 glUniform1i(maskSamplerLocationMask, 1); 1200 break; 1201 } 1202 case ColorProgram: 1203 // Get locations of uniforms for the debug border shader program. 1204 m_colorColorLocation = glGetUniformLocation(programObject, "color"); 1205 break; 1206 case NumberOfPrograms: 1207 return false; 1208 } 1209 1210 return true; 1211} 1212 1213const GLES2Program& LayerRenderer::useProgram(ProgramIndex index) 1214{ 1215 ASSERT(index < NumberOfPrograms); 1216 const GLES2Program& program = m_programs[index]; 1217 if (!program.isValid() && !createProgram(index)) 1218 return program; 1219 1220 glUseProgram(program.m_program); 1221 1222 glEnableVertexAttribArray(program.positionLocation()); 1223 if (index != ColorProgram) 1224 glEnableVertexAttribArray(program.texCoordLocation()); 1225 1226 return program; 1227} 1228 1229const GLES2Program& LayerRenderer::useLayerProgram(LayerData::LayerProgram layerProgram, bool isMask /* = false */) 1230{ 1231 int program = layerProgram; 1232 if (isMask) 1233 program += MaskPrograms; 1234 return useProgram(static_cast<ProgramIndex>(program)); 1235} 1236 1237void LayerRenderingResults::addDirtyRect(const IntRect& rect) 1238{ 1239 IntRect dirtyUnion[NumberOfDirtyRects]; 1240 int smallestIncrease = INT_MAX; 1241 int modifiedRect = 0; 1242 for (int i = 0; i < NumberOfDirtyRects; ++i) { 1243 dirtyUnion[i] = m_dirtyRects[i]; 1244 dirtyUnion[i].unite(rect); 1245 int increase = dirtyUnion[i].width()*dirtyUnion[i].height() - m_dirtyRects[i].width()*m_dirtyRects[i].height(); 1246 if (increase < smallestIncrease) { 1247 smallestIncrease = increase; 1248 modifiedRect = i; 1249 } 1250 } 1251 1252 m_dirtyRects[modifiedRect] = dirtyUnion[modifiedRect]; 1253} 1254 1255bool LayerRenderingResults::isEmpty() const 1256{ 1257 for (int i = 0; i < NumberOfDirtyRects; ++i) { 1258 if (!m_dirtyRects[i].isEmpty()) 1259 return false; 1260 } 1261 return true; 1262} 1263 1264} // namespace WebCore 1265 1266#endif // USE(ACCELERATED_COMPOSITING) 1267