Exemplo n.º 1
0
bool Surface::blitFromContents(Tile* tile)
{
    if (!singleLayer() || !tile || !getFirstLayer() || !getFirstLayer()->content())
        return false;

    if (tile->frontTexture() != tile->lastDrawnTexture()) {
        // 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;
}
Exemplo n.º 2
0
void TileGrid::drawGL(const IntRect& visibleContentArea, float opacity,
                      const TransformationMatrix* transform,
                      const Color* background)
{
    m_area = computeTilesArea(visibleContentArea, m_scale);
    if (m_area.width() == 0 || m_area.height() == 0)
        return;

    float invScale = 1.0 / m_scale;
    const float tileWidth = TilesManager::tileWidth() * invScale;
    const float tileHeight = TilesManager::tileHeight() * invScale;

    int drawn = 0;

    SkRegion missingRegion;
    bool semiOpaqueBaseSurface =
        background ? (background->hasAlpha() && background->alpha() > 0) : false;
    if (semiOpaqueBaseSurface) {
        SkIRect totalArea = SkIRect::MakeXYWH(m_area.x(), m_area.y(),
                                              m_area.width(), m_area.height());
        missingRegion = SkRegion(totalArea);
    }

    bool usePointSampling =
        TilesManager::instance()->shader()->usePointSampling(m_scale, transform);

    float minTileX =  visibleContentArea.x() / tileWidth;
    float minTileY =  visibleContentArea.y() / tileWidth;
    float maxTileWidth = visibleContentArea.maxX() / tileWidth;
    float maxTileHeight = visibleContentArea.maxY() / tileWidth;
    ALOGV("minTileX, minTileY, maxTileWidth, maxTileHeight %f, %f, %f %f",
          minTileX, minTileY, maxTileWidth, maxTileHeight);
    for (unsigned int i = 0; i < m_tiles.size(); i++) {
        Tile* tile = m_tiles[i];

        bool tileInView = tile->isTileVisible(m_area);
        if (tileInView) {
            SkRect rect;
            rect.fLeft = tile->x() * tileWidth;
            rect.fTop = tile->y() * tileHeight;
            rect.fRight = rect.fLeft + tileWidth;
            rect.fBottom = rect.fTop + tileHeight;
            ALOGV("tile %p (layer tile: %d) %d,%d at scale %.2f vs %.2f [ready: %d] dirty: %d",
                  tile, tile->isLayerTile(), tile->x(), tile->y(),
                  tile->scale(), m_scale, tile->isTileReady(), tile->isDirty());

            bool forceBaseBlending = background ? background->hasAlpha() : false;

            float left = std::max(minTileX - tile->x(), 0.0f);
            float top = std::max(minTileY - tile->y(), 0.0f);
            float right = std::min(maxTileWidth - tile->x(), 1.0f);
            float bottom = std::min(maxTileHeight - tile->y(), 1.0f);
            if (left > 1.0f || top > 1.0f || right < 0.0f || bottom < 0.0f) {
                ALOGE("Unexpected portion:left, top, right, bottom %f %f %f %f",
                      left, top, right, bottom);
                left = 0.0f;
                top = 0.0f;
                right = 1.0f;
                bottom = 1.0f;
            }
            FloatRect fillPortion(left, top, right - left, bottom - top);

            bool success = tile->drawGL(opacity, rect, m_scale, transform,
                                        forceBaseBlending, usePointSampling, fillPortion);
            if (semiOpaqueBaseSurface && success) {
                // Cut the successful drawn tile area from the missing region.
                missingRegion.op(SkIRect::MakeXYWH(tile->x(), tile->y(), 1, 1),
                                 SkRegion::kDifference_Op);
            }
            if (tile->frontTexture())
                drawn++;
        }

        // log tile information for base, high res tiles
        if (m_isBaseSurface && background)
            TilesManager::instance()->getProfiler()->nextTile(tile, invScale, tileInView);
    }

    // Draw missing Regions with blend turned on
    if (semiOpaqueBaseSurface)
        drawMissingRegion(missingRegion, opacity, background);

    ALOGV("TG %p drew %d tiles, scale %f",
          this, drawn, m_scale);
}