diff options
Diffstat (limited to 'dm')
-rw-r--r-- | dm/DM.cpp | 8 | ||||
-rw-r--r-- | dm/DMSrcSink.cpp | 158 | ||||
-rw-r--r-- | dm/DMSrcSink.h | 12 |
3 files changed, 165 insertions, 13 deletions
@@ -92,6 +92,8 @@ DEFINE_int32(shard, 0, "Which shard do I run?"); DEFINE_string(mskps, "", "Directory to read mskps from, or a single mskp file."); DEFINE_bool(forceRasterPipeline, false, "sets gSkForceRasterPipelineBlitter"); +DEFINE_bool(ddl, false, "If true, use DeferredDisplayLists for GPU SKP rendering."); + #if SK_SUPPORT_GPU DEFINE_pathrenderer_flag; #endif @@ -773,7 +775,11 @@ static bool gather_srcs() { push_src("gm", "", new GMSrc(r->factory())); } - gather_file_srcs<SKPSrc>(FLAGS_skps, "skp"); + if (FLAGS_ddl) { + gather_file_srcs<DDLSKPSrc>(FLAGS_skps, "skp"); + } else { + gather_file_srcs<SKPSrc>(FLAGS_skps, "skp"); + } gather_file_srcs<MSKPSrc>(FLAGS_mskps, "mskp"); #if defined(SK_XML) gather_file_srcs<SVGSrc>(FLAGS_svgs, "svg"); diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp index e14e1f9963..dc8a913fa1 100644 --- a/dm/DMSrcSink.cpp +++ b/dm/DMSrcSink.cpp @@ -19,6 +19,7 @@ #include "SkData.h" #include "SkDebugCanvas.h" #include "SkDeferredCanvas.h" +#include "SkDeferredDisplayListRecorder.h" #include "SkDocument.h" #include "SkExecutor.h" #include "SkImageGenerator.h" @@ -39,9 +40,11 @@ #include "SkRandom.h" #include "SkRecordDraw.h" #include "SkRecorder.h" +#include "SkSurfaceCharacterization.h" #include "SkSVGCanvas.h" #include "SkStream.h" #include "SkSwizzler.h" +#include "SkTaskGroup.h" #include "SkTLogic.h" #include <cmath> #include <functional> @@ -1140,37 +1143,51 @@ Name ColorCodecSrc::name() const { /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -static const SkRect kSKPViewport = {0,0, 1000,1000}; +static const SkRect kSKPViewport = {0, 0, 1000, 1000}; -SKPSrc::SKPSrc(Path path) : fPath(path) {} +SKPSrc::SKPSrc(Path path) : fPath(path) { } -Error SKPSrc::draw(SkCanvas* canvas) const { - std::unique_ptr<SkStream> stream = SkStream::MakeFromFile(fPath.c_str()); +static sk_sp<SkPicture> read_skp(const char* path) { + std::unique_ptr<SkStream> stream = SkStream::MakeFromFile(path); if (!stream) { - return SkStringPrintf("Couldn't read %s.", fPath.c_str()); + return nullptr; } sk_sp<SkPicture> pic(SkPicture::MakeFromStream(stream.get())); if (!pic) { - return SkStringPrintf("Couldn't decode %s as a picture.", fPath.c_str()); + return nullptr; } stream = nullptr; // Might as well drop this when we're done with it. + return pic; +} + +Error SKPSrc::draw(SkCanvas* canvas) const { + sk_sp<SkPicture> pic = read_skp(fPath.c_str()); + if (!pic) { + return SkStringPrintf("Couldn't read %s.", fPath.c_str()); + } + canvas->clipRect(kSKPViewport); canvas->drawPicture(pic); return ""; } -SkISize SKPSrc::size() const { - std::unique_ptr<SkStream> stream = SkStream::MakeFromFile(fPath.c_str()); +static SkRect get_cull_rect_for_skp(const char* path) { + std::unique_ptr<SkStream> stream = SkStream::MakeFromFile(path); if (!stream) { - return {0, 0}; + return SkRect::MakeEmpty(); } SkPictInfo info; if (!SkPicture::InternalOnly_StreamIsSKP(stream.get(), &info)) { - return {0, 0}; + return SkRect::MakeEmpty(); } - SkRect viewport = kSKPViewport; - if (!viewport.intersect(info.fCullRect)) { + + return info.fCullRect; +} + +SkISize SKPSrc::size() const { + SkRect viewport = get_cull_rect_for_skp(fPath.c_str()); + if (!viewport.intersect(kSKPViewport)) { return {0, 0}; } return viewport.roundOut().size(); @@ -1179,6 +1196,123 @@ SkISize SKPSrc::size() const { Name SKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); } /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + +static const int kNumDDLXTiles = 4; +static const int kNumDDLYTiles = 4; +static const int kDDLTileSize = 1024; +static const SkRect kDDLSKPViewport = { 0, 0, + kNumDDLXTiles * kDDLTileSize, + kNumDDLYTiles * kDDLTileSize }; + +DDLSKPSrc::DDLSKPSrc(Path path) : fPath(path) { } + +Error DDLSKPSrc::draw(SkCanvas* canvas) const { + class TileData { + public: + // Note: we could just pass in surface characterization + TileData(sk_sp<SkSurface> surf, const SkIRect& clip) + : fSurface(std::move(surf)) + , fClip(clip) { + SkAssertResult(fSurface->characterize(&fCharacterization)); + } + + // This method operates in parallel + void preprocess(SkPicture* pic) { + SkDeferredDisplayListRecorder recorder(fCharacterization); + + SkCanvas* subCanvas = recorder.getCanvas(); + + subCanvas->clipRect(SkRect::MakeWH(fClip.width(), fClip.height())); + subCanvas->translate(-fClip.fLeft, -fClip.fTop); + + // Note: in this use case we only render a picture to the deferred canvas + // but, more generally, clients will use arbitrary draw calls. + subCanvas->drawPicture(pic); + + fDisplayList = recorder.detach(); + } + + // This method operates serially + void draw() { + fSurface->draw(fDisplayList.get()); + } + + // This method also operates serially + void compose(SkCanvas* dst) { + sk_sp<SkImage> img = fSurface->makeImageSnapshot(); + dst->save(); + dst->clipRect(SkRect::Make(fClip)); + dst->drawImage(std::move(img), fClip.fLeft, fClip.fTop); + dst->restore(); + } + + private: + sk_sp<SkSurface> fSurface; + SkIRect fClip; // in the device space of the destination canvas + std::unique_ptr<SkDeferredDisplayList> fDisplayList; + SkSurfaceCharacterization fCharacterization; + }; + + SkTArray<TileData> tileData; + tileData.reserve(16); + + sk_sp<SkPicture> pic = read_skp(fPath.c_str()); + if (!pic) { + return SkStringPrintf("Couldn't read %s.", fPath.c_str()); + } + + const SkRect cullRect = pic->cullRect(); + + // All the destination tiles are the same size + const SkImageInfo tileII = SkImageInfo::MakeN32Premul(kDDLTileSize, kDDLTileSize); + + // First, create the destination tiles + for (int y = 0; y < kNumDDLYTiles; ++y) { + for (int x = 0; x < kNumDDLXTiles; ++x) { + SkRect clip = SkRect::MakeXYWH(x * kDDLTileSize, y * kDDLTileSize, + kDDLTileSize, kDDLTileSize); + + if (!clip.intersect(cullRect)) { + continue; + } + + tileData.push_back(TileData(canvas->makeSurface(tileII), clip.roundOut())); + } + } + + // Second, run the cpu pre-processing in threads + SkTaskGroup().batch(tileData.count(), [&](int i) { + tileData[i].preprocess(pic.get()); + }); + + // Third, synchronously render the display lists into the dest tiles + // TODO: it would be cool to not wait until all the tiles are drawn to begin + // drawing to the GPU + for (int i = 0; i < tileData.count(); ++i) { + tileData[i].draw(); + } + + // Finally, compose the drawn tiles into the result + // Note: the separation between the tiles and the final composition better + // matches Chrome but costs us a copy + for (int i = 0; i < tileData.count(); ++i) { + tileData[i].compose(canvas); + } + + return ""; +} + +SkISize DDLSKPSrc::size() const { + SkRect viewport = get_cull_rect_for_skp(fPath.c_str()); + if (!viewport.intersect(kDDLSKPViewport)) { + return {0, 0}; + } + return viewport.roundOut().size(); +} + +Name DDLSKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); } + +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ #if defined(SK_XML) // Used when the image doesn't have an intrinsic size. static const SkSize kDefaultSVGSize = {1000, 1000}; diff --git a/dm/DMSrcSink.h b/dm/DMSrcSink.h index c1af4d01b5..26c32f59b7 100644 --- a/dm/DMSrcSink.h +++ b/dm/DMSrcSink.h @@ -248,6 +248,18 @@ private: Path fPath; }; +// DeferredDisplayList flavor +class DDLSKPSrc : public Src { +public: + explicit DDLSKPSrc(Path path); + + Error draw(SkCanvas*) const override; + SkISize size() const override; + Name name() const override; +private: + Path fPath; +}; + #if defined(SK_XML) } // namespace DM |