aboutsummaryrefslogtreecommitdiffhomepage
path: root/dm/DMSrcSink.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dm/DMSrcSink.cpp')
-rw-r--r--dm/DMSrcSink.cpp158
1 files changed, 146 insertions, 12 deletions
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};