From 9e6835da41e344ef3c4c35036fabfdb0a4146c33 Mon Sep 17 00:00:00 2001 From: robertphillips Date: Wed, 22 Oct 2014 05:33:52 -0700 Subject: Track nested picture xform state for layer hoisting The accumulated matrix state of any enclosing SkPictures must be stored separate from the picture-local CTM. Any setMatrix calls inside a layer need to replace the picture-local CTM but concatenate with the enclosing SkPicture transform state (and the transform state needed to translate the layer to the correct location in the cached GrTexture). Review URL: https://codereview.chromium.org/639863005 --- src/gpu/GrLayerHoister.cpp | 49 ++++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 19 deletions(-) (limited to 'src/gpu/GrLayerHoister.cpp') diff --git a/src/gpu/GrLayerHoister.cpp b/src/gpu/GrLayerHoister.cpp index 929c12285d..3ae0e2d45f 100644 --- a/src/gpu/GrLayerHoister.cpp +++ b/src/gpu/GrLayerHoister.cpp @@ -25,13 +25,14 @@ static void prepare_for_hoisting(GrLayerCache* layerCache, SkTDArray* recycled) { const SkPicture* pict = info.fPicture ? info.fPicture : topLevelPicture; + SkMatrix combined = SkMatrix::Concat(info.fPreMat, info.fLocalMat); + GrCachedLayer* layer = layerCache->findLayerOrCreate(pict->uniqueID(), info.fSaveLayerOpID, info.fRestoreOpID, layerRect, - info.fOriginXform, + combined, info.fPaint); - GrTextureDesc desc; desc.fFlags = kRenderTarget_GrTextureFlagBit; desc.fWidth = layerRect.width(); @@ -65,7 +66,8 @@ static void prepare_for_hoisting(GrLayerCache* layerCache, hl->fLayer = layer; hl->fPicture = pict; hl->fOffset = SkIPoint::Make(layerRect.fLeft, layerRect.fTop); - hl->fCTM = info.fOriginXform; + hl->fLocalMat = info.fLocalMat; + hl->fPreMat = info.fPreMat; } // Return true if any layers are suitable for hoisting @@ -113,7 +115,6 @@ bool GrLayerHoister::FindLayersToHoist(GrContext* context, continue; } - SkIRect ir; layerRect.roundOut(&ir); @@ -144,10 +145,12 @@ static void convert_layers_to_replacements(const SkTDArray& laye GrCachedLayer* layer = layers[i].fLayer; const SkPicture* picture = layers[i].fPicture; + SkMatrix combined = SkMatrix::Concat(layers[i].fPreMat, layers[i].fLocalMat); + GrReplacements::ReplacementInfo* layerInfo = replacements->newReplacement(picture->uniqueID(), layer->start(), - layers[i].fCTM); + combined); layerInfo->fStop = layer->stop(); layerInfo->fPos = layers[i].fOffset; @@ -171,7 +174,8 @@ static void convert_layers_to_replacements(const SkTDArray& laye } } -void GrLayerHoister::DrawLayers(const SkTDArray& atlased, +void GrLayerHoister::DrawLayers(GrContext* context, + const SkTDArray& atlased, const SkTDArray& nonAtlased, const SkTDArray& recycled, GrReplacements* replacements) { @@ -183,14 +187,17 @@ void GrLayerHoister::DrawLayers(const SkTDArray& atlased, SkCanvas* atlasCanvas = surface->getCanvas(); - SkPaint paint; - paint.setColor(SK_ColorTRANSPARENT); - paint.setXfermode(SkXfermode::Create(SkXfermode::kSrc_Mode))->unref(); + SkPaint clearPaint; + clearPaint.setColor(SK_ColorTRANSPARENT); + clearPaint.setXfermode(SkXfermode::Create(SkXfermode::kSrc_Mode))->unref(); for (int i = 0; i < atlased.count(); ++i) { - GrCachedLayer* layer = atlased[i].fLayer; + const GrCachedLayer* layer = atlased[i].fLayer; const SkPicture* pict = atlased[i].fPicture; const SkIPoint offset = atlased[i].fOffset; + SkDEBUGCODE(const SkPaint* layerPaint = layer->paint();) + + SkASSERT(!layerPaint || !layerPaint->getImageFilter()); atlasCanvas->save(); @@ -204,7 +211,7 @@ void GrLayerHoister::DrawLayers(const SkTDArray& atlased, // Since 'clear' doesn't respect the clip we need to draw a rect // TODO: ensure none of the atlased layers contain a clear call! - atlasCanvas->drawRect(bound, paint); + atlasCanvas->drawRect(bound, clearPaint); // info.fCTM maps the layer's top/left to the origin. // Since this layer is atlased, the top/left corner needs @@ -213,11 +220,13 @@ void GrLayerHoister::DrawLayers(const SkTDArray& atlased, initialCTM.setTranslate(SkIntToScalar(-offset.fX), SkIntToScalar(-offset.fY)); initialCTM.postTranslate(bound.fLeft, bound.fTop); - + initialCTM.postConcat(atlased[i].fPreMat); + atlasCanvas->translate(SkIntToScalar(-offset.fX), SkIntToScalar(-offset.fY)); atlasCanvas->translate(bound.fLeft, bound.fTop); - atlasCanvas->concat(atlased[i].fCTM); + atlasCanvas->concat(atlased[i].fPreMat); + atlasCanvas->concat(atlased[i].fLocalMat); SkRecordPartialDraw(*pict->fRecord.get(), atlasCanvas, bound, layer->start()+1, layer->stop(), initialCTM); @@ -232,7 +241,7 @@ void GrLayerHoister::DrawLayers(const SkTDArray& atlased, for (int i = 0; i < nonAtlased.count(); ++i) { GrCachedLayer* layer = nonAtlased[i].fLayer; const SkPicture* pict = nonAtlased[i].fPicture; - const SkIPoint offset = nonAtlased[i].fOffset; + const SkIPoint& offset = nonAtlased[i].fOffset; // Each non-atlased layer has its own GrTexture SkAutoTUnref surface(SkSurface::NewRenderTargetDirect( @@ -240,6 +249,8 @@ void GrLayerHoister::DrawLayers(const SkTDArray& atlased, SkCanvas* layerCanvas = surface->getCanvas(); + SkASSERT(0 == layer->rect().fLeft && 0 == layer->rect().fTop); + // Add a rect clip to make sure the rendering doesn't // extend beyond the boundaries of the atlased sub-rect SkRect bound = SkRect::MakeXYWH(SkIntToScalar(layer->rect().fLeft), @@ -252,12 +263,12 @@ void GrLayerHoister::DrawLayers(const SkTDArray& atlased, layerCanvas->clear(SK_ColorTRANSPARENT); SkMatrix initialCTM; - initialCTM.setTranslate(SkIntToScalar(-offset.fX), - SkIntToScalar(-offset.fY)); + initialCTM.setTranslate(SkIntToScalar(-offset.fX), SkIntToScalar(-offset.fY)); + initialCTM.postConcat(nonAtlased[i].fPreMat); - layerCanvas->translate(SkIntToScalar(-offset.fX), - SkIntToScalar(-offset.fY)); - layerCanvas->concat(nonAtlased[i].fCTM); + layerCanvas->translate(SkIntToScalar(-offset.fX), SkIntToScalar(-offset.fY)); + layerCanvas->concat(nonAtlased[i].fPreMat); + layerCanvas->concat(nonAtlased[i].fLocalMat); SkRecordPartialDraw(*pict->fRecord.get(), layerCanvas, bound, layer->start()+1, layer->stop(), initialCTM); -- cgit v1.2.3