From d61ef01f176328619d29045da3ec72e4732276b6 Mon Sep 17 00:00:00 2001 From: robertphillips Date: Wed, 8 Oct 2014 05:17:02 -0700 Subject: [PATCH] Expose layer hoisting API in GrContext This CL exposes the layer hoisting API in GrContext for use in SkMultiPictureDraw::draw. It basically mirrors what SkGpuDevice::EXPERIMENTAL_drawPicture has been doing. Review URL: https://codereview.chromium.org/533673002 --- src/core/SkMultiPictureDraw.cpp | 65 +++++++++++++++++++++++++++++++-- src/gpu/GrLayerHoister.cpp | 33 ++++++++++------- src/gpu/GrLayerHoister.h | 42 +++++++++++---------- src/gpu/SkGpuDevice.cpp | 10 ++--- 4 files changed, 107 insertions(+), 43 deletions(-) diff --git a/src/core/SkMultiPictureDraw.cpp b/src/core/SkMultiPictureDraw.cpp index eb1e55e550..19b26ca607 100644 --- a/src/core/SkMultiPictureDraw.cpp +++ b/src/core/SkMultiPictureDraw.cpp @@ -5,6 +5,11 @@ * found in the LICENSE file. */ +#if SK_SUPPORT_GPU +#include "GrLayerHoister.h" +#include "GrRecordReplaceDraw.h" +#endif + #include "SkCanvas.h" #include "SkMultiPictureDraw.h" #include "SkPicture.h" @@ -50,13 +55,67 @@ void SkMultiPictureDraw::add(SkCanvas* canvas, } } +#undef SK_IGNORE_GPU_LAYER_HOISTING +#define SK_IGNORE_GPU_LAYER_HOISTING 1 + void SkMultiPictureDraw::draw() { + +#ifndef SK_IGNORE_GPU_LAYER_HOISTING + GrContext* context = NULL; + + SkTDArray atlased, nonAtlased, recycled; + for (int i = 0; i < fDrawData.count(); ++i) { - fDrawData[i].canvas->drawPicture(fDrawData[i].picture, - &fDrawData[i].matrix, - fDrawData[i].paint); + if (fDrawData[i].canvas->getGrContext() && + !fDrawData[i].paint && fDrawData[i].matrix.isIdentity()) { + SkASSERT(NULL == context || context == fDrawData[i].canvas->getGrContext()); + context = fDrawData[i].canvas->getGrContext(); + + // TODO: this path always tries to optimize pictures. Should we + // switch to this API approach (vs. SkCanvas::EXPERIMENTAL_optimize)? + fDrawData[i].canvas->EXPERIMENTAL_optimize(fDrawData[i].picture); + + SkRect clipBounds; + if (!fDrawData[i].canvas->getClipBounds(&clipBounds)) { + continue; + } + + GrLayerHoister::FindLayersToHoist(context, fDrawData[i].picture, + clipBounds, &atlased, &nonAtlased, &recycled); + } } + GrReplacements replacements; + + if (NULL != context) { + GrLayerHoister::DrawLayers(atlased, nonAtlased, recycled, &replacements); + } +#endif + + for (int i = 0; i < fDrawData.count(); ++i) { +#ifndef SK_IGNORE_GPU_LAYER_HOISTING + if (fDrawData[i].canvas->getGrContext() && + !fDrawData[i].paint && fDrawData[i].matrix.isIdentity()) { + // Render the entire picture using new layers + const SkMatrix initialMatrix = fDrawData[i].canvas->getTotalMatrix(); + + GrRecordReplaceDraw(fDrawData[i].picture, fDrawData[i].canvas, + &replacements, initialMatrix, NULL); + } else +#endif + { + fDrawData[i].canvas->drawPicture(fDrawData[i].picture, + &fDrawData[i].matrix, + fDrawData[i].paint); + } + } + +#ifndef SK_IGNORE_GPU_LAYER_HOISTING + if (NULL != context) { + GrLayerHoister::UnlockLayers(context, atlased, nonAtlased, recycled); + } +#endif + this->reset(); } diff --git a/src/gpu/GrLayerHoister.cpp b/src/gpu/GrLayerHoister.cpp index 2e42ead857..8b0079369d 100644 --- a/src/gpu/GrLayerHoister.cpp +++ b/src/gpu/GrLayerHoister.cpp @@ -14,14 +14,18 @@ #include "SkSurface.h" // Return true if any layers are suitable for hoisting -bool GrLayerHoister::FindLayersToHoist(const SkPicture* topLevelPicture, +bool GrLayerHoister::FindLayersToHoist(GrContext* context, + const SkPicture* topLevelPicture, const SkRect& query, - SkTDArray* atlased, - SkTDArray* nonAtlased, - SkTDArray* recycled, - GrLayerCache* layerCache) { + SkTDArray* atlased, + SkTDArray* nonAtlased, + SkTDArray* recycled) { bool anyHoisted = false; + GrLayerCache* layerCache = context->getLayerCache(); + + layerCache->processDeletedPictures(); + SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey(); const SkPicture::AccelData* topLevelData = topLevelPicture->EXPERIMENTAL_getAccelData(key); @@ -102,7 +106,7 @@ bool GrLayerHoister::FindLayersToHoist(const SkPicture* topLevelPicture, continue; } - HoistedLayer* hl; + GrHoistedLayer* hl; if (needsRendering) { if (layer->isAtlased()) { @@ -130,7 +134,7 @@ 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& layers, +static void convert_layers_to_replacements(const SkTDArray& layers, GrReplacements* replacements) { // TODO: just replace GrReplacements::ReplacementInfo with GrCachedLayer? for (int i = 0; i < layers.count(); ++i) { @@ -164,9 +168,9 @@ static void convert_layers_to_replacements(const SkTDArray& atlased, - const SkTDArray& nonAtlased, - const SkTDArray& recycled, +void GrLayerHoister::DrawLayers(const SkTDArray& atlased, + const SkTDArray& nonAtlased, + const SkTDArray& recycled, GrReplacements* replacements) { // Render the atlased layers that require it if (atlased.count() > 0) { @@ -276,10 +280,11 @@ static void unlock_layer_in_cache(GrLayerCache* layerCache, #endif } -void GrLayerHoister::UnlockLayers(GrLayerCache* layerCache, - const SkTDArray& atlased, - const SkTDArray& nonAtlased, - const SkTDArray& recycled) { +void GrLayerHoister::UnlockLayers(GrContext* context, + const SkTDArray& atlased, + const SkTDArray& nonAtlased, + const SkTDArray& recycled) { + GrLayerCache* layerCache = context->getLayerCache(); for (int i = 0; i < atlased.count(); ++i) { unlock_layer_in_cache(layerCache, atlased[i].fPicture, atlased[i].fLayer); diff --git a/src/gpu/GrLayerHoister.h b/src/gpu/GrLayerHoister.h index 58b3f4870b..7f49881e21 100644 --- a/src/gpu/GrLayerHoister.h +++ b/src/gpu/GrLayerHoister.h @@ -16,6 +16,14 @@ struct GrCachedLayer; class GrReplacements; struct SkRect; +class GrHoistedLayer { +public: + const SkPicture* fPicture; + GrCachedLayer* fLayer; + SkIPoint fOffset; + SkMatrix fCTM; +}; + // This class collects the layer hoisting functionality in one place. // For each picture rendering: // FindLayersToHoist should be called once to collect the required layers @@ -23,29 +31,23 @@ struct SkRect; // UnlockLayers should be called once to allow the texture resources to be recycled class GrLayerHoister { public: - struct HoistedLayer { - const SkPicture* fPicture; - GrCachedLayer* fLayer; - SkIPoint fOffset; - SkMatrix fCTM; - }; /** Find the layers in 'topLevelPicture' that need hoisting. Note that the discovered layers can be inside nested sub-pictures. + @param context Owner of the layer cache (the source of new layers) @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 recycled Out parameter storing layers that need hoisting but not rendering - @param layerCache The source of new layers Return true if any layers are suitable for hoisting; false otherwise */ - static bool FindLayersToHoist(const SkPicture* topLevelPicture, + static bool FindLayersToHoist(GrContext* context, + const SkPicture* topLevelPicture, const SkRect& query, - SkTDArray* altased, - SkTDArray* nonAtlased, - SkTDArray* recycled, - GrLayerCache* layerCache); + SkTDArray* atlased, + SkTDArray* nonAtlased, + SkTDArray* recycled); /** Draw the specified layers into either the atlas or free floating textures. @param atlased The layers to be drawn into the atlas @@ -54,21 +56,21 @@ public: replacements object @param replacements The replacement structure to fill in with the rendered layer info */ - static void DrawLayers(const SkTDArray& atlased, - const SkTDArray& nonAtlased, - const SkTDArray& recycled, + static void DrawLayers(const SkTDArray& atlased, + const SkTDArray& nonAtlased, + const SkTDArray& recycled, GrReplacements* replacements); /** Unlock unneeded layers in the layer cache. - @param layerCache holder of the locked layers + @param context Owner of the layer cache (and thus the layers) @param atlased Unneeded layers in the atlas @param nonAtlased Unneeded layers in their own textures @param recycled Unneeded layers that did not require rendering */ - static void UnlockLayers(GrLayerCache* layerCache, - const SkTDArray& atlased, - const SkTDArray& nonAtlased, - const SkTDArray& recycled); + static void UnlockLayers(GrContext* context, + const SkTDArray& atlased, + const SkTDArray& nonAtlased, + const SkTDArray& recycled); }; #endif diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index 93c2085d9d..ad01a363f0 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -1849,17 +1849,15 @@ bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture return false; } - fContext->getLayerCache()->processDeletedPictures(); - SkRect clipBounds; if (!mainCanvas->getClipBounds(&clipBounds)) { return true; } - SkTDArray atlased, nonAtlased, recycled; + SkTDArray atlased, nonAtlased, recycled; - if (!GrLayerHoister::FindLayersToHoist(mainPicture, clipBounds, &atlased, &nonAtlased, - &recycled, fContext->getLayerCache())) { + if (!GrLayerHoister::FindLayersToHoist(fContext, mainPicture, clipBounds, + &atlased, &nonAtlased, &recycled)) { return false; } @@ -1872,7 +1870,7 @@ bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture GrRecordReplaceDraw(mainPicture, mainCanvas, &replacements, initialMatrix, NULL); - GrLayerHoister::UnlockLayers(fContext->getLayerCache(), atlased, nonAtlased, recycled); + GrLayerHoister::UnlockLayers(fContext, atlased, nonAtlased, recycled); return true; }