bool Surface::blitFromContents(Tile* tile) { if (!singleLayer() || !tile || !getFirstLayer() || !getFirstLayer()->content()) return false; LayerContent* content = getFirstLayer()->content(); // Extract the dirty rect from the region. Note that this is *NOT* constrained // to this tile IntRect dirtyRect = tile->dirtyArea().getBounds(); IntRect tileRect = IntRect(tile->x() * TilesManager::tileWidth(), tile->y() * TilesManager::tileHeight(), TilesManager::tileWidth(), TilesManager::tileHeight()); FloatRect tileRectInDoc = tileRect; tileRectInDoc.scale(1 / tile->scale()); dirtyRect.intersect(enclosingIntRect(tileRectInDoc)); PrerenderedInval* prerenderedInval = content->prerenderForRect(dirtyRect); if (!prerenderedInval || prerenderedInval->bitmap.isNull()) return false; SkBitmap sourceBitmap = prerenderedInval->bitmap; // Calculate the screen rect that is dirty, then intersect it with the // tile's screen rect so that we end up with the pixels we need to blit FloatRect screenDirty = dirtyRect; screenDirty.scale(tile->scale()); IntRect enclosingScreenDirty = enclosingIntRect(screenDirty); enclosingScreenDirty.intersect(tileRect); if (enclosingScreenDirty.isEmpty()) return false; // Make sure the screen area we want to blit is contained by the // prerendered screen area if (!prerenderedInval->screenArea.contains(enclosingScreenDirty)) { ALOGD("prerendered->screenArea " INT_RECT_FORMAT " doesn't contain " "enclosingScreenDirty " INT_RECT_FORMAT, INT_RECT_ARGS(prerenderedInval->screenArea), INT_RECT_ARGS(enclosingScreenDirty)); return false; } IntPoint origin = prerenderedInval->screenArea.location(); SkBitmap subset; subset.setConfig(sourceBitmap.config(), enclosingScreenDirty.width(), enclosingScreenDirty.height()); subset.allocPixels(); int topOffset = enclosingScreenDirty.y() - prerenderedInval->screenArea.y(); int leftOffset = enclosingScreenDirty.x() - prerenderedInval->screenArea.x(); if (!GLUtils::deepCopyBitmapSubset(sourceBitmap, subset, leftOffset, topOffset)) return false; // Now upload SkIRect textureInval = SkIRect::MakeXYWH(enclosingScreenDirty.x() - tileRect.x(), enclosingScreenDirty.y() - tileRect.y(), enclosingScreenDirty.width(), enclosingScreenDirty.height()); GLUtils::updateTextureWithBitmap(tile->frontTexture()->m_ownTextureId, subset, textureInval); tile->onBlitUpdate(); return true; }
void Surface::prepareGL(bool layerTilesDisabled, bool updateWithBlit) { bool tilesDisabled = layerTilesDisabled && !isBase(); if (!m_surfaceBacking) { ALOGV("prepareGL on Surf %p, no SurfBack, needsTexture? %d", this, m_surfaceBacking, needsTexture()); if (needsTexture() || (isBase() && layerTilesDisabled)) m_surfaceBacking = new SurfaceBacking(isBase()); else return; } if (tilesDisabled) { m_surfaceBacking->discardTextures(); } else { bool allowZoom = hasText(); // only allow for scale > 1 if painting vectors IntRect prepareArea = computePrepareArea(); IntRect fullArea = fullContentArea(); ALOGV("prepareGL on Surf %p with SurfBack %p, %d layers, first layer %s (%d) " "prepareArea(%d, %d - %d x %d) fullArea(%d, %d - %d x %d)", this, m_surfaceBacking, m_layers.size(), getFirstLayer()->subclassName().ascii().data(), getFirstLayer()->uniqueId(), prepareArea.x(), prepareArea.y(), prepareArea.width(), prepareArea.height(), fullArea.x(), fullArea.y(), fullArea.width(), fullArea.height()); m_surfaceBacking->prepareGL(getFirstLayer()->state(), allowZoom, prepareArea, fullArea, this, useAggressiveRendering(), updateWithBlit); } for (size_t i = 0; i < m_layers.size(); i++) { LayerContent* content = m_layers[i]->content(); if (content) content->clearPrerenders(); } }
bool Surface::tryUpdateSurface(Surface* oldSurface) { if (!needsTexture() || !oldSurface->needsTexture()) return false; // merge surfaces based on first layer ID if (getFirstLayer()->uniqueId() != oldSurface->getFirstLayer()->uniqueId()) return false; m_surfaceBacking = oldSurface->m_surfaceBacking; SkSafeRef(m_surfaceBacking); ALOGV("%p taking old SurfBack %p from surface %p, nt %d", this, m_surfaceBacking, oldSurface, oldSurface->needsTexture()); if (!m_surfaceBacking) { // no SurfBack to inval, so don't worry about it. return true; } SkRegion invalRegion; bool fullInval = false; if (singleLayer() && oldSurface->singleLayer()) { // both are single matching layers, simply apply inval SkRegion* layerInval = getFirstLayer()->getInvalRegion(); invalRegion = *layerInval; if (isBase()) { // the base layer paints outside it's content area to ensure the // viewport is convered, so fully invalidate all tiles if its size // changes to ensure no stale content remains LayerContent* newContent = getFirstLayer()->content(); LayerContent* oldContent = oldSurface->getFirstLayer()->content(); fullInval = newContent->width() != oldContent->width() || newContent->height() != oldContent->height(); } } else { fullInval = m_layers.size() != oldSurface->m_layers.size(); if (!fullInval) { for (unsigned int i = 0; i < m_layers.size(); i++) { if ((m_layers[i]->uniqueId() != oldSurface->m_layers[i]->uniqueId()) || (m_layers[i]->fullContentAreaMapped() != oldSurface->m_layers[i]->fullContentAreaMapped())) { // layer list has changed, fully invalidate // TODO: partially invalidate based on layer size/position fullInval = true; break; } else if (!m_layers[i]->getInvalRegion()->isEmpty()) { // merge layer inval - translate the layer's inval region into surface coordinates // TODO: handle scale/3d transform mapping FloatRect layerPos = m_layers[i]->fullContentAreaMapped(); m_layers[i]->getInvalRegion()->translate(layerPos.x(), layerPos.y()); invalRegion.op(*(m_layers[i]->getInvalRegion()), SkRegion::kUnion_Op); } } } } if (fullInval) invalRegion.setRect(-1e8, -1e8, 2e8, 2e8); m_surfaceBacking->markAsDirty(invalRegion); return true; }
bool Surface::blitFromContents(Tile* tile) { if (!singleLayer() || !tile || !getFirstLayer() || !getFirstLayer()->content()) return false; if (tile->frontTexture() != tile->lastDrawnTexture()) { // CAPPFIX_FLICKERING: fix flickering issue at floating browser mode return false; // CAPPFIX_FLICKERING_END // the below works around an issue where glTexSubImage2d can't update a // texture that hasn't drawn yet by drawing it off screen. // glFlush() and glFinish() work also, but are likely more wasteful. SkRect rect = SkRect::MakeXYWH(-100, -100, 0, 0); FloatRect fillPortion(0, 0, 0, 0); tile->frontTexture()->drawGL(false, rect, 1.0f, 0, false, true, fillPortion); } LayerContent* content = getFirstLayer()->content(); // Extract the dirty rect from the region. Note that this is *NOT* constrained // to this tile IntRect dirtyRect = tile->dirtyArea().getBounds(); IntRect tileRect = IntRect(tile->x() * TilesManager::tileWidth(), tile->y() * TilesManager::tileHeight(), TilesManager::tileWidth(), TilesManager::tileHeight()); FloatRect tileRectInDoc = tileRect; tileRectInDoc.scale(1 / tile->scale()); dirtyRect.intersect(enclosingIntRect(tileRectInDoc)); PrerenderedInval* prerenderedInval = content->prerenderForRect(dirtyRect); if (!prerenderedInval || prerenderedInval->bitmap.isNull()) return false; SkBitmap sourceBitmap = prerenderedInval->bitmap; // Calculate the screen rect that is dirty, then intersect it with the // tile's screen rect so that we end up with the pixels we need to blit FloatRect screenDirty = dirtyRect; screenDirty.scale(tile->scale()); IntRect enclosingScreenDirty = enclosingIntRect(screenDirty); enclosingScreenDirty.intersect(tileRect); if (enclosingScreenDirty.isEmpty()) return false; // Make sure the screen area we want to blit is contained by the // prerendered screen area if (!prerenderedInval->screenArea.contains(enclosingScreenDirty)) { ALOGD("prerendered->screenArea " INT_RECT_FORMAT " doesn't contain " "enclosingScreenDirty " INT_RECT_FORMAT, INT_RECT_ARGS(prerenderedInval->screenArea), INT_RECT_ARGS(enclosingScreenDirty)); return false; } IntPoint origin = prerenderedInval->screenArea.location(); SkBitmap subset; subset.setConfig(sourceBitmap.config(), enclosingScreenDirty.width(), enclosingScreenDirty.height()); subset.allocPixels(); int topOffset = enclosingScreenDirty.y() - prerenderedInval->screenArea.y(); int leftOffset = enclosingScreenDirty.x() - prerenderedInval->screenArea.x(); if (!GLUtils::deepCopyBitmapSubset(sourceBitmap, subset, leftOffset, topOffset)) return false; // Now upload SkIRect textureInval = SkIRect::MakeXYWH(enclosingScreenDirty.x() - tileRect.x(), enclosingScreenDirty.y() - tileRect.y(), enclosingScreenDirty.width(), enclosingScreenDirty.height()); GLUtils::updateTextureWithBitmap(tile->frontTexture()->m_ownTextureId, subset, textureInval); tile->onBlitUpdate(); return true; }