1 /* 2 * Copyright 2012, 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 "Surface" 27 #define LOG_NDEBUG 1 28 29 #include "config.h" 30 #include "Surface.h" 31 32 #include "AndroidLog.h" 33 #include "BaseLayerAndroid.h" 34 #include "ClassTracker.h" 35 #include "LayerAndroid.h" 36 #include "LayerContent.h" 37 #include "GLWebViewState.h" 38 #include "PrerenderedInval.h" 39 #include "SkCanvas.h" 40 #include "SurfaceBacking.h" 41 #include "Tile.h" 42 #include "TileTexture.h" 43 #include "TilesManager.h" 44 45 #include <wtf/text/CString.h> 46 47 // Surfaces with an area larger than 2048*2048 should never be unclipped 48 #define MAX_FULL_CONTENT_AREA 4194304 49 50 namespace WebCore { 51 52 Surface::Surface() 53 : m_surfaceBacking(0) 54 , m_needsTexture(false) 55 , m_hasText(false) 56 { 57 #ifdef DEBUG_COUNT 58 ClassTracker::instance()->increment("Surface"); 59 #endif 60 } 61 62 Surface::~Surface() 63 { 64 for (unsigned int i = 0; i < m_layers.size(); i++) 65 SkSafeUnref(m_layers[i]); 66 if (m_surfaceBacking) 67 SkSafeUnref(m_surfaceBacking); 68 #ifdef DEBUG_COUNT 69 ClassTracker::instance()->decrement("Surface"); 70 #endif 71 } 72 73 bool Surface::tryUpdateSurface(Surface* oldSurface) 74 { 75 if (!needsTexture() || !oldSurface->needsTexture()) 76 return false; 77 78 // merge surfaces based on first layer ID 79 if (getFirstLayer()->uniqueId() != oldSurface->getFirstLayer()->uniqueId()) 80 return false; 81 82 m_surfaceBacking = oldSurface->m_surfaceBacking; 83 SkSafeRef(m_surfaceBacking); 84 85 ALOGV("%p taking old SurfBack %p from surface %p, nt %d", 86 this, m_surfaceBacking, oldSurface, oldSurface->needsTexture()); 87 88 if (!m_surfaceBacking) { 89 // no SurfBack to inval, so don't worry about it. 90 return true; 91 } 92 93 SkRegion invalRegion; 94 bool fullInval = false; 95 if (singleLayer() && oldSurface->singleLayer()) { 96 // both are single matching layers, simply apply inval 97 SkRegion* layerInval = getFirstLayer()->getInvalRegion(); 98 invalRegion = *layerInval; 99 100 if (isBase()) { 101 // the base layer paints outside it's content area to ensure the 102 // viewport is convered, so fully invalidate all tiles if its size 103 // changes to ensure no stale content remains 104 LayerContent* newContent = getFirstLayer()->content(); 105 LayerContent* oldContent = oldSurface->getFirstLayer()->content(); 106 fullInval = newContent->width() != oldContent->width() 107 || newContent->height() != oldContent->height(); 108 } 109 } else { 110 fullInval = m_layers.size() != oldSurface->m_layers.size(); 111 if (!fullInval) { 112 for (unsigned int i = 0; i < m_layers.size(); i++) { 113 if ((m_layers[i]->uniqueId() != oldSurface->m_layers[i]->uniqueId()) 114 || (m_layers[i]->fullContentAreaMapped() != oldSurface->m_layers[i]->fullContentAreaMapped())) { 115 // layer list has changed, fully invalidate 116 // TODO: partially invalidate based on layer size/position 117 fullInval = true; 118 break; 119 } else if (!m_layers[i]->getInvalRegion()->isEmpty()) { 120 // merge layer inval - translate the layer's inval region into surface coordinates 121 // TODO: handle scale/3d transform mapping 122 FloatRect layerPos = m_layers[i]->fullContentAreaMapped(); 123 m_layers[i]->getInvalRegion()->translate(layerPos.x(), layerPos.y()); 124 invalRegion.op(*(m_layers[i]->getInvalRegion()), SkRegion::kUnion_Op); 125 } 126 } 127 } 128 } 129 130 if (fullInval) 131 invalRegion.setRect(-1e8, -1e8, 2e8, 2e8); 132 133 m_surfaceBacking->markAsDirty(invalRegion); 134 return true; 135 } 136 137 void Surface::addLayer(LayerAndroid* layer, const TransformationMatrix& transform) 138 { 139 m_layers.append(layer); 140 SkSafeRef(layer); 141 142 m_needsTexture |= layer->needsTexture(); 143 m_hasText |= layer->hasText(); 144 145 // add this layer's size to the surface's area 146 // TODO: handle scale/3d transform mapping 147 IntRect rect = enclosingIntRect(layer->fullContentAreaMapped()); 148 149 if (layer->needsTexture()) { 150 if (m_fullContentArea.isEmpty()) { 151 m_drawTransform = transform; 152 m_drawTransform.translate3d(-rect.x(), -rect.y(), 0); 153 m_fullContentArea = rect; 154 } else 155 m_fullContentArea.unite(rect); 156 ALOGV("Surf %p adding LA %p, size " INT_RECT_FORMAT 157 " now fullContentArea " INT_RECT_FORMAT, 158 this, layer, INT_RECT_ARGS(rect), INT_RECT_ARGS(m_fullContentArea)); 159 } 160 161 if (isBase()) 162 m_background = static_cast<BaseLayerAndroid*>(layer)->getBackgroundColor(); 163 } 164 165 IntRect Surface::visibleContentArea(bool force3dContentVisible) const 166 { 167 if (singleLayer()) 168 return getFirstLayer()->visibleContentArea(force3dContentVisible); 169 170 IntRect rect = m_fullContentArea; 171 172 // clip with the viewport in content coordinate 173 IntRect contentViewport(TilesManager::instance()->shader()->contentViewport()); 174 rect.intersect(contentViewport); 175 176 // TODO: handle recursive layer clip 177 178 return rect; 179 } 180 181 IntRect Surface::fullContentArea() 182 { 183 if (singleLayer()) 184 return getFirstLayer()->fullContentArea(); 185 return m_fullContentArea; 186 } 187 188 bool Surface::useAggressiveRendering() 189 { 190 // When the background is semi-opaque, 0 < alpha < 255, we had to turn off 191 // low res to avoid artifacts from double drawing. 192 // TODO: avoid double drawing for low res tiles. 193 return isBase() 194 && (!m_background.alpha() 195 || !m_background.hasAlpha()); 196 } 197 198 void Surface::prepareGL(bool layerTilesDisabled, bool updateWithBlit) 199 { 200 bool tilesDisabled = layerTilesDisabled && !isBase(); 201 if (!m_surfaceBacking) { 202 ALOGV("prepareGL on Surf %p, no SurfBack, needsTexture? %d", 203 this, m_surfaceBacking, needsTexture()); 204 205 if (needsTexture() || (isBase() && layerTilesDisabled)) 206 m_surfaceBacking = new SurfaceBacking(isBase()); 207 else 208 return; 209 } 210 211 if (tilesDisabled) { 212 m_surfaceBacking->discardTextures(); 213 } else { 214 bool allowZoom = hasText(); // only allow for scale > 1 if painting vectors 215 IntRect prepareArea = computePrepareArea(); 216 IntRect fullArea = fullContentArea(); 217 218 ALOGV("prepareGL on Surf %p with SurfBack %p, %d layers, first layer %s (%d) " 219 "prepareArea(%d, %d - %d x %d) fullArea(%d, %d - %d x %d)", 220 this, m_surfaceBacking, m_layers.size(), 221 getFirstLayer()->subclassName().ascii().data(), 222 getFirstLayer()->uniqueId(), 223 prepareArea.x(), prepareArea.y(), prepareArea.width(), prepareArea.height(), 224 fullArea.x(), fullArea.y(), fullArea.width(), fullArea.height()); 225 226 m_surfaceBacking->prepareGL(getFirstLayer()->state(), allowZoom, 227 prepareArea, fullArea, 228 this, useAggressiveRendering(), updateWithBlit); 229 } 230 for (size_t i = 0; i < m_layers.size(); i++) { 231 LayerContent* content = m_layers[i]->content(); 232 if (content) 233 content->clearPrerenders(); 234 } 235 } 236 237 bool Surface::drawGL(bool layerTilesDisabled) 238 { 239 bool tilesDisabled = layerTilesDisabled && !isBase(); 240 if (singleLayer() && !getFirstLayer()->visible()) 241 return false; 242 243 if (!isBase()) { 244 FloatRect drawClip = getFirstLayer()->drawClip(); 245 if (!singleLayer()) { 246 for (unsigned int i = 1; i < m_layers.size(); i++) 247 drawClip.unite(m_layers[i]->drawClip()); 248 } 249 FloatRect clippingRect = TilesManager::instance()->shader()->rectInInvViewCoord(drawClip); 250 TilesManager::instance()->shader()->clip(clippingRect); 251 } 252 253 bool askRedraw = false; 254 if (m_surfaceBacking && !tilesDisabled) { 255 ALOGV("drawGL on Surf %p with SurfBack %p, first layer %s (%d)", this, m_surfaceBacking, 256 getFirstLayer()->subclassName().ascii().data(), getFirstLayer()->uniqueId()); 257 258 bool force3dContentVisible = true; 259 IntRect drawArea = visibleContentArea(force3dContentVisible); 260 m_surfaceBacking->drawGL(drawArea, opacity(), drawTransform(), 261 useAggressiveRendering(), background()); 262 } 263 264 // draw member layers (draws image textures, glextras) 265 for (unsigned int i = 0; i < m_layers.size(); i++) { 266 if (m_layers[i]->drawGL(tilesDisabled)) { 267 m_layers[i]->addDirtyArea(); 268 askRedraw = true; 269 } 270 } 271 272 return askRedraw; 273 } 274 275 void Surface::swapTiles(bool calculateFrameworkInvals) 276 { 277 if (!m_surfaceBacking) 278 return; 279 280 if (m_surfaceBacking->swapTiles() && calculateFrameworkInvals) 281 addFrameworkInvals(); 282 } 283 284 void Surface::addFrameworkInvals() 285 { 286 // Let's return an inval area to framework that will 287 // contain all of our layers' areas 288 for (unsigned int i = 0; i < m_layers.size(); i++) 289 m_layers[i]->addDirtyArea(); 290 } 291 292 bool Surface::isReady() 293 { 294 if (!m_surfaceBacking) 295 return true; 296 297 return m_surfaceBacking->isReady(); 298 } 299 300 bool Surface::isMissingContent() 301 { 302 if (!m_surfaceBacking) 303 return true; 304 305 return m_surfaceBacking->isMissingContent(); 306 } 307 308 bool Surface::canUpdateWithBlit() 309 { 310 // If we don't have a texture, we have nothing to update and thus can take 311 // the fast path 312 if (!needsTexture()) 313 return true; 314 // If we have a surface backing that isn't ready, we can't update with a blit 315 // If it is ready, then check to see if it is dirty. We can only call isDirty() 316 // if isReady() returns true 317 if (!m_surfaceBacking) 318 return false; 319 if (!m_surfaceBacking->isReady()) 320 return false; 321 if (!m_surfaceBacking->isDirty()) 322 return true; 323 if (!singleLayer()) 324 return false; 325 return getFirstLayer()->canUpdateWithBlit(); 326 } 327 328 IntRect Surface::computePrepareArea() 329 { 330 IntRect area; 331 332 if (!getFirstLayer()->contentIsScrollable() 333 && !isBase() 334 && getFirstLayer()->state()->layersRenderingMode() == GLWebViewState::kAllTextures) { 335 336 area = fullContentArea(); 337 338 double total = ((double) area.width()) * ((double) area.height()); 339 if (total > MAX_FULL_CONTENT_AREA) 340 area = visibleContentArea(); 341 } else 342 area = visibleContentArea(); 343 344 return area; 345 } 346 347 void Surface::computeTexturesAmount(TexturesResult* result) 348 { 349 if (!m_surfaceBacking || isBase()) 350 return; 351 352 353 LayerAndroid* layer = 0; 354 if (singleLayer()) 355 layer = getFirstLayer(); 356 357 m_surfaceBacking->computeTexturesAmount(result, visibleContentArea(), 358 fullContentArea(), layer); 359 } 360 361 bool Surface::isBase() 362 { 363 // base layer surface 364 // - doesn't use layer tiles (disables blending, doesn't compute textures amount) 365 // - ignores clip rects 366 // - only prepares clippedArea 367 return getFirstLayer()->subclassType() == LayerAndroid::BaseLayer; 368 } 369 370 bool Surface::paint(SkCanvas* canvas) 371 { 372 if (singleLayer()) { 373 getFirstLayer()->contentDraw(canvas, Layer::UnmergedLayers); 374 375 // TODO: double buffer by disabling SurfaceCollection swaps and position 376 // updates until painting complete 377 378 // In single surface mode, draw layer content onto the base layer 379 if (isBase() 380 && getFirstLayer()->countChildren() 381 && getFirstLayer()->state()->isSingleSurfaceRenderingMode()) { 382 for (int i = 0; i < getFirstLayer()->countChildren(); i++) 383 getFirstLayer()->getChild(i)->drawCanvas(canvas, true, Layer::FlattenedLayers); 384 } 385 } else { 386 SkAutoCanvasRestore acr(canvas, true); 387 SkMatrix matrix; 388 GLUtils::toSkMatrix(matrix, m_drawTransform); 389 390 SkMatrix inverse; 391 inverse.reset(); 392 matrix.invert(&inverse); 393 394 SkMatrix canvasMatrix = canvas->getTotalMatrix(); 395 inverse.postConcat(canvasMatrix); 396 canvas->setMatrix(inverse); 397 398 for (unsigned int i=0; i<m_layers.size(); i++) 399 m_layers[i]->drawCanvas(canvas, false, Layer::MergedLayers); 400 } 401 return true; 402 } 403 404 float Surface::opacity() 405 { 406 if (singleLayer()) 407 return getFirstLayer()->drawOpacity(); 408 return 1.0; 409 } 410 411 Color* Surface::background() 412 { 413 if (!isBase() || !m_background.isValid()) 414 return 0; 415 return &m_background; 416 } 417 418 bool Surface::blitFromContents(Tile* tile) 419 { 420 if (!singleLayer() || !tile || !getFirstLayer() || !getFirstLayer()->content()) 421 return false; 422 423 if (tile->frontTexture() != tile->lastDrawnTexture()) { 424 // the below works around an issue where glTexSubImage2d can't update a 425 // texture that hasn't drawn yet by drawing it off screen. 426 // glFlush() and glFinish() work also, but are likely more wasteful. 427 SkRect rect = SkRect::MakeXYWH(-100, -100, 0, 0); 428 FloatRect fillPortion(0, 0, 0, 0); 429 tile->frontTexture()->drawGL(false, rect, 1.0f, 0, false, true, fillPortion); 430 } 431 LayerContent* content = getFirstLayer()->content(); 432 // Extract the dirty rect from the region. Note that this is *NOT* constrained 433 // to this tile 434 IntRect dirtyRect = tile->dirtyArea().getBounds(); 435 IntRect tileRect = IntRect(tile->x() * TilesManager::tileWidth(), 436 tile->y() * TilesManager::tileHeight(), 437 TilesManager::tileWidth(), 438 TilesManager::tileHeight()); 439 FloatRect tileRectInDoc = tileRect; 440 tileRectInDoc.scale(1 / tile->scale()); 441 dirtyRect.intersect(enclosingIntRect(tileRectInDoc)); 442 PrerenderedInval* prerenderedInval = content->prerenderForRect(dirtyRect); 443 if (!prerenderedInval || prerenderedInval->bitmap.isNull()) 444 return false; 445 SkBitmap sourceBitmap = prerenderedInval->bitmap; 446 // Calculate the screen rect that is dirty, then intersect it with the 447 // tile's screen rect so that we end up with the pixels we need to blit 448 FloatRect screenDirty = dirtyRect; 449 screenDirty.scale(tile->scale()); 450 IntRect enclosingScreenDirty = enclosingIntRect(screenDirty); 451 enclosingScreenDirty.intersect(tileRect); 452 if (enclosingScreenDirty.isEmpty()) 453 return false; 454 // Make sure the screen area we want to blit is contained by the 455 // prerendered screen area 456 if (!prerenderedInval->screenArea.contains(enclosingScreenDirty)) { 457 ALOGD("prerendered->screenArea " INT_RECT_FORMAT " doesn't contain " 458 "enclosingScreenDirty " INT_RECT_FORMAT, 459 INT_RECT_ARGS(prerenderedInval->screenArea), 460 INT_RECT_ARGS(enclosingScreenDirty)); 461 return false; 462 } 463 IntPoint origin = prerenderedInval->screenArea.location(); 464 SkBitmap subset; 465 subset.setConfig(sourceBitmap.config(), enclosingScreenDirty.width(), 466 enclosingScreenDirty.height()); 467 subset.allocPixels(); 468 469 int topOffset = enclosingScreenDirty.y() - prerenderedInval->screenArea.y(); 470 int leftOffset = enclosingScreenDirty.x() - prerenderedInval->screenArea.x(); 471 if (!GLUtils::deepCopyBitmapSubset(sourceBitmap, subset, leftOffset, topOffset)) 472 return false; 473 // Now upload 474 SkIRect textureInval = SkIRect::MakeXYWH(enclosingScreenDirty.x() - tileRect.x(), 475 enclosingScreenDirty.y() - tileRect.y(), 476 enclosingScreenDirty.width(), 477 enclosingScreenDirty.height()); 478 GLUtils::updateTextureWithBitmap(tile->frontTexture()->m_ownTextureId, 479 subset, textureInval); 480 tile->onBlitUpdate(); 481 return true; 482 } 483 484 const TransformationMatrix* Surface::drawTransform() 485 { 486 // single layer surfaces query the layer's draw transform, while multi-layer 487 // surfaces copy the draw transform once, during initialization 488 // TODO: support fixed multi-layer surfaces by querying the changing drawTransform 489 if (singleLayer()) 490 return getFirstLayer()->drawTransform(); 491 492 return &m_drawTransform; 493 } 494 495 } // namespace WebCore 496