diff options
author | robertphillips <robertphillips@google.com> | 2014-09-24 08:52:18 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-09-24 08:52:19 -0700 |
commit | 30d2cc6ff47cb7f981d83e9a536971beec920f61 (patch) | |
tree | 279ab6885df001b92be3ebb2ff696e76c99f471f /src | |
parent | 34a9895baf8b2bf95c4f6944a7914be1a74f1524 (diff) |
Update layer hoisting code to correctly render sub-picture layers
The prior code assumed all layers came from a single picture.
BUG=skia:2315
R=bsalomon@google.com
Author: robertphillips@google.com
Review URL: https://codereview.chromium.org/595543002
Diffstat (limited to 'src')
-rw-r--r-- | src/gpu/GrLayerHoister.cpp | 125 | ||||
-rw-r--r-- | src/gpu/GrLayerHoister.h | 40 | ||||
-rw-r--r-- | src/gpu/GrPictureUtils.cpp | 29 | ||||
-rw-r--r-- | src/gpu/GrPictureUtils.h | 38 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.cpp | 25 |
5 files changed, 132 insertions, 125 deletions
diff --git a/src/gpu/GrLayerHoister.cpp b/src/gpu/GrLayerHoister.cpp index 165716f82d..91d439b304 100644 --- a/src/gpu/GrLayerHoister.cpp +++ b/src/gpu/GrLayerHoister.cpp @@ -14,26 +14,38 @@ #include "SkSurface.h" // Return true if any layers are suitable for hoisting -bool GrLayerHoister::FindLayersToHoist(const GrAccelData *gpuData, +bool GrLayerHoister::FindLayersToHoist(const SkPicture* topLevelPicture, const SkRect& query, - SkTDArray<GrCachedLayer*>* atlased, - SkTDArray<GrCachedLayer*>* nonAtlased, + SkTDArray<HoistedLayer>* atlased, + SkTDArray<HoistedLayer>* nonAtlased, GrLayerCache* layerCache) { bool anyHoisted = false; + SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey(); + + const SkPicture::AccelData* topLevelData = topLevelPicture->EXPERIMENTAL_getAccelData(key); + if (NULL == topLevelData) { + return false; + } + + const GrAccelData *topLevelGPUData = static_cast<const GrAccelData*>(topLevelData); + if (0 == topLevelGPUData->numSaveLayers()) { + return false; + } + // Layer hoisting pre-renders the entire layer since it will be cached and potentially // reused with different clips (e.g., in different tiles). Because of this the // clip will not be limiting the size of the pre-rendered layer. kSaveLayerMaxSize // is used to limit which clips are pre-rendered. static const int kSaveLayerMaxSize = 256; - SkAutoTArray<bool> pullForward(gpuData->numSaveLayers()); + SkAutoTArray<bool> pullForward(topLevelGPUData->numSaveLayers()); // Pre-render all the layers that intersect the query rect - for (int i = 0; i < gpuData->numSaveLayers(); ++i) { + for (int i = 0; i < topLevelGPUData->numSaveLayers(); ++i) { pullForward[i] = false; - const GrAccelData::SaveLayerInfo& info = gpuData->saveLayerInfo(i); + const GrAccelData::SaveLayerInfo& info = topLevelGPUData->saveLayerInfo(i); SkRect layerRect = SkRect::MakeXYWH(SkIntToScalar(info.fOffset.fX), SkIntToScalar(info.fOffset.fY), @@ -61,14 +73,15 @@ bool GrLayerHoister::FindLayersToHoist(const GrAccelData *gpuData, return false; } - atlased->setReserve(atlased->reserved() + gpuData->numSaveLayers()); + atlased->setReserve(atlased->reserved() + topLevelGPUData->numSaveLayers()); // Generate the layer and/or ensure it is locked - for (int i = 0; i < gpuData->numSaveLayers(); ++i) { + for (int i = 0; i < topLevelGPUData->numSaveLayers(); ++i) { if (pullForward[i]) { - const GrAccelData::SaveLayerInfo& info = gpuData->saveLayerInfo(i); + const GrAccelData::SaveLayerInfo& info = topLevelGPUData->saveLayerInfo(i); + const SkPicture* pict = info.fPicture ? info.fPicture : topLevelPicture; - GrCachedLayer* layer = layerCache->findLayerOrCreate(info.fPictureID, + GrCachedLayer* layer = layerCache->findLayerOrCreate(pict->uniqueID(), info.fSaveLayerOpID, info.fRestoreOpID, info.fOffset, @@ -89,11 +102,16 @@ bool GrLayerHoister::FindLayersToHoist(const GrAccelData *gpuData, } if (needsRendering) { + HoistedLayer* info; + if (layer->isAtlased()) { - *atlased->append() = layer; + info = atlased->append(); } else { - *nonAtlased->append() = layer; + info = nonAtlased->append(); } + + info->fLayer = layer; + info->fPicture = pict; } } } @@ -107,42 +125,43 @@ static void wrap_texture(GrTexture* texture, int width, int height, SkBitmap* re result->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, texture)))->unref(); } -static void convert_layers_to_replacements(const SkTDArray<GrCachedLayer*>& layers, +static void convert_layers_to_replacements(const SkTDArray<GrLayerHoister::HoistedLayer>& layers, GrReplacements* replacements) { // TODO: just replace GrReplacements::ReplacementInfo with GrCachedLayer? for (int i = 0; i < layers.count(); ++i) { GrReplacements::ReplacementInfo* layerInfo = replacements->push(); - layerInfo->fStart = layers[i]->start(); - layerInfo->fStop = layers[i]->stop(); - layerInfo->fPos = layers[i]->offset();; + layerInfo->fStart = layers[i].fLayer->start(); + layerInfo->fStop = layers[i].fLayer->stop(); + layerInfo->fPos = layers[i].fLayer->offset();; SkBitmap bm; - wrap_texture(layers[i]->texture(), - !layers[i]->isAtlased() ? layers[i]->rect().width() - : layers[i]->texture()->width(), - !layers[i]->isAtlased() ? layers[i]->rect().height() - : layers[i]->texture()->height(), + wrap_texture(layers[i].fLayer->texture(), + !layers[i].fLayer->isAtlased() ? layers[i].fLayer->rect().width() + : layers[i].fLayer->texture()->width(), + !layers[i].fLayer->isAtlased() ? layers[i].fLayer->rect().height() + : layers[i].fLayer->texture()->height(), &bm); layerInfo->fImage = SkImage::NewTexture(bm); - layerInfo->fPaint = layers[i]->paint() ? SkNEW_ARGS(SkPaint, (*layers[i]->paint())) : NULL; + layerInfo->fPaint = layers[i].fLayer->paint() + ? SkNEW_ARGS(SkPaint, (*layers[i].fLayer->paint())) + : NULL; - layerInfo->fSrcRect = SkIRect::MakeXYWH(layers[i]->rect().fLeft, - layers[i]->rect().fTop, - layers[i]->rect().width(), - layers[i]->rect().height()); + layerInfo->fSrcRect = SkIRect::MakeXYWH(layers[i].fLayer->rect().fLeft, + layers[i].fLayer->rect().fTop, + layers[i].fLayer->rect().width(), + layers[i].fLayer->rect().height()); } } -void GrLayerHoister::DrawLayers(const SkPicture* picture, - const SkTDArray<GrCachedLayer*>& atlased, - const SkTDArray<GrCachedLayer*>& nonAtlased, +void GrLayerHoister::DrawLayers(const SkTDArray<HoistedLayer>& atlased, + const SkTDArray<HoistedLayer>& nonAtlased, GrReplacements* replacements) { // Render the atlased layers that require it if (atlased.count() > 0) { // All the atlased layers are rendered into the same GrTexture SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect( - atlased[0]->texture()->asRenderTarget(), NULL)); + atlased[0].fLayer->texture()->asRenderTarget(), NULL)); SkCanvas* atlasCanvas = surface->getCanvas(); @@ -151,7 +170,8 @@ void GrLayerHoister::DrawLayers(const SkPicture* picture, paint.setXfermode(SkXfermode::Create(SkXfermode::kSrc_Mode))->unref(); for (int i = 0; i < atlased.count(); ++i) { - GrCachedLayer* layer = atlased[i]; + GrCachedLayer* layer = atlased[i].fLayer; + const SkPicture* pict = atlased[i].fPicture; atlasCanvas->save(); @@ -180,7 +200,7 @@ void GrLayerHoister::DrawLayers(const SkPicture* picture, atlasCanvas->translate(bound.fLeft, bound.fTop); atlasCanvas->concat(layer->ctm()); - SkRecordPartialDraw(*picture->fRecord.get(), atlasCanvas, bound, + SkRecordPartialDraw(*pict->fRecord.get(), atlasCanvas, bound, layer->start()+1, layer->stop(), initialCTM); atlasCanvas->restore(); @@ -191,7 +211,8 @@ void GrLayerHoister::DrawLayers(const SkPicture* picture, // Render the non-atlased layers that require it for (int i = 0; i < nonAtlased.count(); ++i) { - GrCachedLayer* layer = nonAtlased[i]; + GrCachedLayer* layer = nonAtlased[i].fLayer; + const SkPicture* pict = nonAtlased[i].fPicture; // Each non-atlased layer has its own GrTexture SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect( @@ -218,7 +239,7 @@ void GrLayerHoister::DrawLayers(const SkPicture* picture, SkIntToScalar(-layer->offset().fY)); layerCanvas->concat(layer->ctm()); - SkRecordPartialDraw(*picture->fRecord.get(), layerCanvas, bound, + SkRecordPartialDraw(*pict->fRecord.get(), layerCanvas, bound, layer->start()+1, layer->stop(), initialCTM); layerCanvas->flush(); @@ -228,33 +249,35 @@ void GrLayerHoister::DrawLayers(const SkPicture* picture, convert_layers_to_replacements(nonAtlased, replacements); } -void GrLayerHoister::UnlockLayers(GrLayerCache* layerCache, const SkPicture* picture) { - SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey(); +static void unlock_layer_in_cache(GrLayerCache* layerCache, + const SkPicture* picture, + GrCachedLayer* layer) { + layerCache->unlock(layer); - const SkPicture::AccelData* data = picture->EXPERIMENTAL_getAccelData(key); - SkASSERT(data); +#if DISABLE_CACHING + // This code completely clears out the atlas. It is required when + // caching is disabled so the atlas doesn't fill up and force more + // free floating layers + layerCache->purge(picture->uniqueID()); +#endif +} - const GrAccelData *gpuData = static_cast<const GrAccelData*>(data); - SkASSERT(0 != gpuData->numSaveLayers()); +void GrLayerHoister::UnlockLayers(GrLayerCache* layerCache, + const SkTDArray<HoistedLayer>& atlased, + const SkTDArray<HoistedLayer>& nonAtlased) { - // unlock the layers - for (int i = 0; i < gpuData->numSaveLayers(); ++i) { - const GrAccelData::SaveLayerInfo& info = gpuData->saveLayerInfo(i); + for (int i = 0; i < atlased.count(); ++i) { + unlock_layer_in_cache(layerCache, atlased[i].fPicture, atlased[i].fLayer); + } - GrCachedLayer* layer = layerCache->findLayer(picture->uniqueID(), - info.fSaveLayerOpID, - info.fRestoreOpID, - info.fOffset, - info.fOriginXform); - layerCache->unlock(layer); + for (int i = 0; i < nonAtlased.count(); ++i) { + unlock_layer_in_cache(layerCache, nonAtlased[i].fPicture, nonAtlased[i].fLayer); } #if DISABLE_CACHING // This code completely clears out the atlas. It is required when // caching is disabled so the atlas doesn't fill up and force more // free floating layers - layerCache->purge(picture->uniqueID()); - layerCache->purgeAll(); #endif } diff --git a/src/gpu/GrLayerHoister.h b/src/gpu/GrLayerHoister.h index a3b97e328a..acf1901096 100644 --- a/src/gpu/GrLayerHoister.h +++ b/src/gpu/GrLayerHoister.h @@ -23,37 +23,43 @@ struct SkRect; // UnlockLayers should be called once to allow the texture resources to be recycled class GrLayerHoister { public: - /** Find the layers in 'gpuData' that need hoisting. - @param gpuData Acceleration structure containing layer information for a picture - @param query The rectangle that is about to be drawn. - @param atlased Out parameter storing the layers that should be hoisted to the atlas - @param nonAtlased Out parameter storing the layers that should be hoisted stand alone + struct HoistedLayer { + const SkPicture* fPicture; + GrCachedLayer* fLayer; + }; + + /** Find the layers in 'topLevelPicture' that need hoisting. Note that the discovered + layers can be inside nested sub-pictures. + @param topLevelPicture The top-level picture that is about to be rendered + @param query The rectangle that is about to be drawn. + @param atlased Out parameter storing the layers that should be hoisted to the atlas + @param nonAtlased Out parameter storing the layers that should be hoisted stand alone @param layerCache The source of new layers Return true if any layers are suitable for hoisting; false otherwise */ - static bool FindLayersToHoist(const GrAccelData *gpuData, + static bool FindLayersToHoist(const SkPicture* topLevelPicture, const SkRect& query, - SkTDArray<GrCachedLayer*>* altased, - SkTDArray<GrCachedLayer*>* nonAtlased, + SkTDArray<HoistedLayer>* altased, + SkTDArray<HoistedLayer>* nonAtlased, GrLayerCache* layerCache); - /** Draw the specified layers of 'picture' into either the atlas or free - floating textures. - @param picture The picture containing the layers + /** Draw the specified layers into either the atlas or free floating textures. @param atlased The layers to be drawn into the atlas @param nonAtlased The layers to be drawn into their own textures @oaram replacements The replacement structure to fill in with the rendered layer info */ - static void DrawLayers(const SkPicture* picture, - const SkTDArray<GrCachedLayer*>& atlased, - const SkTDArray<GrCachedLayer*>& nonAtlased, + static void DrawLayers(const SkTDArray<HoistedLayer>& atlased, + const SkTDArray<HoistedLayer>& nonAtlased, GrReplacements* replacements); - /** Unlock all the layers associated with picture in the layer cache. + /** Unlock unneeded layers in the layer cache. @param layerCache holder of the locked layers - @pmara picture the source of the locked layers + @param atlased Unneeded layers in the atlas + @param nonAtlased Unneeded layers in their own textures */ - static void UnlockLayers(GrLayerCache* layerCache, const SkPicture* picture); + static void UnlockLayers(GrLayerCache* layerCache, + const SkTDArray<HoistedLayer>& atlased, + const SkTDArray<HoistedLayer>& nonAtlased); }; #endif diff --git a/src/gpu/GrPictureUtils.cpp b/src/gpu/GrPictureUtils.cpp index 0cc1f1e065..a4f32e7e02 100644 --- a/src/gpu/GrPictureUtils.cpp +++ b/src/gpu/GrPictureUtils.cpp @@ -110,8 +110,6 @@ private: this->updateStackForSaveLayer(); - GrAccelData::SaveLayerInfo dst; - // TODO: need to store an SkRect in GrAccelData::SaveLayerInfo? SkRect srcRect = SkRect::MakeXYWH(SkIntToScalar(src.fOffset.fX), SkIntToScalar(src.fOffset.fY), @@ -120,25 +118,24 @@ private: SkIRect newClip(fCurrentClipBounds); newClip.intersect(this->adjustAndMap(srcRect, dp.paint)); + GrAccelData::SaveLayerInfo& dst = fAccelData->addSaveLayerInfo(); + dst.fValid = true; - dst.fPictureID = dp.picture->uniqueID(); + // If src.fPicture is NULL the layer is in dp.picture; otherwise + // it belongs to a sub-picture. + dst.fPicture = src.fPicture ? src.fPicture : static_cast<const SkPicture*>(dp.picture); + dst.fPicture->ref(); dst.fSize = SkISize::Make(newClip.width(), newClip.height()); dst.fOffset = SkIPoint::Make(newClip.fLeft, newClip.fTop); dst.fOriginXform = *fCTM; dst.fOriginXform.postConcat(src.fOriginXform); - - if (NULL == src.fPaint) { - dst.fPaint = NULL; - } else { + if (src.fPaint) { dst.fPaint = SkNEW_ARGS(SkPaint, (*src.fPaint)); } - dst.fSaveLayerOpID = src.fSaveLayerOpID; dst.fRestoreOpID = src.fRestoreOpID; dst.fHasNestedLayers = src.fHasNestedLayers; dst.fIsNested = fSaveLayersInStack > 0 || src.fIsNested; - - fAccelData->addSaveLayerInfo(dst); } } @@ -182,26 +179,20 @@ private: --fSaveLayersInStack; - GrAccelData::SaveLayerInfo slInfo; + GrAccelData::SaveLayerInfo& slInfo = fAccelData->addSaveLayerInfo(); slInfo.fValid = true; - slInfo.fPictureID = fPictureID; + SkASSERT(NULL == slInfo.fPicture); // This layer is in the top-most picture slInfo.fSize = SkISize::Make(si.fBounds.width(), si.fBounds.height()); slInfo.fOffset = SkIPoint::Make(si.fBounds.fLeft, si.fBounds.fTop); slInfo.fOriginXform = *fCTM; - - if (NULL == si.fPaint) { - slInfo.fPaint = NULL; - } else { + if (si.fPaint) { slInfo.fPaint = SkNEW_ARGS(SkPaint, (*si.fPaint)); } - slInfo.fSaveLayerOpID = si.fStartIndex; slInfo.fRestoreOpID = fCurrentOp; slInfo.fHasNestedLayers = si.fHasNestedSaveLayer; slInfo.fIsNested = fSaveLayersInStack > 0; - - fAccelData->addSaveLayerInfo(slInfo); } // Returns true if rect was meaningfully adjusted for the effects of paint, diff --git a/src/gpu/GrPictureUtils.h b/src/gpu/GrPictureUtils.h index 55b294ac69..f9bab805d9 100644 --- a/src/gpu/GrPictureUtils.h +++ b/src/gpu/GrPictureUtils.h @@ -9,21 +9,27 @@ #define GrPictureUtils_DEFINED #include "SkPicture.h" -#include "SkTDArray.h" +#include "SkTArray.h" // This class encapsulates the GPU-backend-specific acceleration data // for a single SkPicture class GrAccelData : public SkPicture::AccelData { public: // Information about a given saveLayer in an SkPicture - struct SaveLayerInfo { - // True if the SaveLayerInfo is valid. False if either 'fOffset' is - // invalid (due to a non-invertible CTM) or 'fPaint' is NULL (due - // to a non-copyable paint). + class SaveLayerInfo { + public: + SaveLayerInfo() : fPicture(NULL), fPaint(NULL) {} + ~SaveLayerInfo() { SkSafeUnref(fPicture); SkDELETE(fPaint); } + + // True if the SaveLayerInfo is valid. False if 'fOffset' is + // invalid (due to a non-invertible CTM). + // TODO: remove fValid bool fValid; - // ID of the picture containing the layer. This can be the ID of - // a sub-picture embedded within the picture owning the GrAccelData - uint32_t fPictureID; + // The picture owning the layer. If the owning picture is the top-most + // one (i.e., the picture for which this GrAccelData was created) then + // this pointer is NULL. If it is a nested picture then the pointer + // is non-NULL and owns a ref on the picture. + const SkPicture* fPicture; // The size of the saveLayer SkISize fSize; // The matrix state in which this layer's draws must occur. It does not @@ -32,8 +38,7 @@ public: // The offset that needs to be passed to drawBitmap to correctly // position the pre-rendered layer. It is in device space. SkIPoint fOffset; - // The paint to use on restore. NULL if the paint was not copyable (and - // thus that this layer should not be pulled forward). + // The paint to use on restore. Can be NULL since it is optional. const SkPaint* fPaint; // The ID of this saveLayer in the picture. 0 is an invalid ID. size_t fSaveLayerOpID; @@ -48,16 +53,9 @@ public: GrAccelData(Key key) : INHERITED(key) { } - virtual ~GrAccelData() { - for (int i = 0; i < fSaveLayerInfo.count(); ++i) { - SkDELETE(fSaveLayerInfo[i].fPaint); - } - } + virtual ~GrAccelData() { } - void addSaveLayerInfo(const SaveLayerInfo& info) { - SkASSERT(info.fSaveLayerOpID < info.fRestoreOpID); - *fSaveLayerInfo.push() = info; - } + SaveLayerInfo& addSaveLayerInfo() { return fSaveLayerInfo.push_back(); } int numSaveLayers() const { return fSaveLayerInfo.count(); } @@ -72,7 +70,7 @@ public: static SkPicture::AccelData::Key ComputeAccelDataKey(); private: - SkTDArray<SaveLayerInfo> fSaveLayerInfo; + SkTArray<SaveLayerInfo, true> fSaveLayerInfo; typedef SkPicture::AccelData INHERITED; }; diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index bebc3980bd..b6476134d3 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -1838,7 +1838,7 @@ void SkGpuDevice::EXPERIMENTAL_optimize(const SkPicture* picture) { fContext->getLayerCache()->trackPicture(picture); } -bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture* picture, +bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture* mainPicture, const SkMatrix* matrix, const SkPaint* paint) { // todo: should handle these natively if (matrix || paint) { @@ -1847,38 +1847,27 @@ bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture fContext->getLayerCache()->processDeletedPictures(); - SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey(); - - const SkPicture::AccelData* data = picture->EXPERIMENTAL_getAccelData(key); - if (NULL == data) { - return false; - } - - const GrAccelData *gpuData = static_cast<const GrAccelData*>(data); - if (0 == gpuData->numSaveLayers()) { - return false; - } - SkRect clipBounds; if (!mainCanvas->getClipBounds(&clipBounds)) { return true; } - SkTDArray<GrCachedLayer*> atlased, nonAtlased; + SkTDArray<GrLayerHoister::HoistedLayer> atlased, nonAtlased; - if (!GrLayerHoister::FindLayersToHoist(gpuData, clipBounds, &atlased, &nonAtlased, + if (!GrLayerHoister::FindLayersToHoist(mainPicture, clipBounds, &atlased, &nonAtlased, fContext->getLayerCache())) { return false; } GrReplacements replacements; - GrLayerHoister::DrawLayers(picture, atlased, nonAtlased, &replacements); + GrLayerHoister::DrawLayers(atlased, nonAtlased, &replacements); // Render the entire picture using new layers - GrRecordReplaceDraw(*picture->fRecord, mainCanvas, picture->fBBH.get(), &replacements, NULL); + GrRecordReplaceDraw(*mainPicture->fRecord, mainCanvas, mainPicture->fBBH.get(), + &replacements, NULL); - GrLayerHoister::UnlockLayers(fContext->getLayerCache(), picture); + GrLayerHoister::UnlockLayers(fContext->getLayerCache(), atlased, nonAtlased); return true; } |