SkPictureGpuAnalyzer

Stateful helper for gathering multi-picture GPU stats.

Exposes the existing SkPicture GPU veto semantics, while preserving
the SKP impl (which has some nice properties: lazy, hierarchical,
cached per pic).

R=reed@google.com,bsalomon@google.com
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1974833003

Review-Url: https://codereview.chromium.org/1974833003
This commit is contained in:
fmalita 2016-05-13 11:40:07 -07:00 committed by Commit bot
parent b2df0c2702
commit 796e365999
7 changed files with 157 additions and 10 deletions

View File

@ -206,6 +206,7 @@
'<(skia_src_path)/core/SkPathRef.cpp',
'<(skia_src_path)/core/SkPerspIter.h',
'<(skia_src_path)/core/SkPicture.cpp',
'<(skia_src_path)/core/SkPictureAnalyzer.cpp',
'<(skia_src_path)/core/SkPictureCommon.h',
'<(skia_src_path)/core/SkPictureContentInfo.cpp',
'<(skia_src_path)/core/SkPictureContentInfo.h',
@ -385,6 +386,7 @@
'<(skia_include_path)/core/SkPathMeasure.h',
'<(skia_include_path)/core/SkPathRef.h',
'<(skia_include_path)/core/SkPicture.h',
'<(skia_include_path)/core/SkPictureAnalyzer.h',
'<(skia_include_path)/core/SkPictureRecorder.h',
'<(skia_include_path)/core/SkPixelRef.h',
'<(skia_include_path)/core/SkPoint.h',

View File

@ -153,8 +153,10 @@ public:
static bool InternalOnly_StreamIsSKP(SkStream*, SkPictInfo*);
static bool InternalOnly_BufferIsSKP(SkReadBuffer*, SkPictInfo*);
#ifdef SK_SUPPORT_LEGACY_PICTURE_GPUVETO
/** Return true if the picture is suitable for rendering on the GPU. */
bool suitableForGpuRasterization(GrContext*, const char** whyNot = NULL) const;
#endif
// Sent via SkMessageBus from destructor.
struct DeletionMessage { int32_t fUniqueID; }; // TODO: -> uint32_t?
@ -190,6 +192,7 @@ private:
friend class SkPictureData;
virtual int numSlowPaths() const = 0;
friend class SkPictureGpuAnalyzer;
friend struct SkPathCounter;
// V35: Store SkRect (rather then width & height) in header

View File

@ -0,0 +1,52 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkPictureAnalyzer_DEFINED
#define SkPictureAnalyzer_DEFINED
#include "SkRefCnt.h"
#include "SkTypes.h"
#if SK_SUPPORT_GPU
#include "GrContext.h"
class SkPicture;
/** \class SkPictureGpuAnalyzer
Gathers GPU-related statistics for one or more SkPictures.
*/
class SK_API SkPictureGpuAnalyzer final : public SkNoncopyable {
public:
explicit SkPictureGpuAnalyzer(sk_sp<GrContextThreadSafeProxy> = nullptr);
explicit SkPictureGpuAnalyzer(const sk_sp<SkPicture>& picture,
sk_sp<GrContextThreadSafeProxy> = nullptr);
/**
* Process the given picture and accumulate its stats.
*/
void analyze(const SkPicture*);
/**
* Reset all accumulated stats.
*/
void reset();
/**
* Returns true if the analyzed pictures are suitable for rendering on the GPU.
*/
bool suitableForGpuRasterization(const char** whyNot = nullptr) const;
private:
uint32_t fNumSlowPaths;
typedef SkNoncopyable INHERITED;
};
#endif // SK_SUPPORT_GPU
#endif // SkPictureAnalyzer_DEFINED

View File

@ -219,6 +219,7 @@ void SkPicture::flatten(SkWriteBuffer& buffer) const {
}
}
#ifdef SK_SUPPORT_LEGACY_PICTURE_GPUVETO
bool SkPicture::suitableForGpuRasterization(GrContext*, const char** whyNot) const {
if (this->numSlowPaths() > 5) {
if (whyNot) { *whyNot = "Too many slow paths (either concave or dashed)."; }
@ -226,6 +227,7 @@ bool SkPicture::suitableForGpuRasterization(GrContext*, const char** whyNot) con
}
return true;
}
#endif
// Global setting to disable security precautions for serialization.
void SkPicture::SetPictureIOSecurityPrecautionsEnabled_Dangerous(bool set) {

View File

@ -0,0 +1,50 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkPicture.h"
#include "SkPictureAnalyzer.h"
#if SK_SUPPORT_GPU
namespace {
inline bool veto_predicate(uint32_t numSlowPaths) {
return numSlowPaths > 5;
}
} // anonymous namespace
SkPictureGpuAnalyzer::SkPictureGpuAnalyzer(sk_sp<GrContextThreadSafeProxy> /* unused ATM */)
: fNumSlowPaths(0) { }
SkPictureGpuAnalyzer::SkPictureGpuAnalyzer(const sk_sp<SkPicture>& picture,
sk_sp<GrContextThreadSafeProxy> ctx)
: SkPictureGpuAnalyzer(std::move(ctx)) {
this->analyze(picture.get());
}
void SkPictureGpuAnalyzer::analyze(const SkPicture* picture) {
if (!picture || veto_predicate(fNumSlowPaths)) {
return;
}
fNumSlowPaths += picture->numSlowPaths();
}
void SkPictureGpuAnalyzer::reset() {
fNumSlowPaths = 0;
}
bool SkPictureGpuAnalyzer::suitableForGpuRasterization(const char** whyNot) const {
if(veto_predicate(fNumSlowPaths)) {
if (whyNot) { *whyNot = "Too many slow paths (either concave or dashed)."; }
return false;
}
return true;
}
#endif // SK_SUPPORT_GPU

View File

@ -20,6 +20,7 @@
#include "SkMD5.h"
#include "SkPaint.h"
#include "SkPicture.h"
#include "SkPictureAnalyzer.h"
#include "SkPictureRecorder.h"
#include "SkPictureUtils.h"
#include "SkPixelRef.h"
@ -158,7 +159,8 @@ static void test_gpu_veto(skiatest::Reporter* reporter) {
// path effects currently render an SkPicture undesireable for GPU rendering
const char *reason = nullptr;
REPORTER_ASSERT(reporter, !picture->suitableForGpuRasterization(nullptr, &reason));
REPORTER_ASSERT(reporter,
!SkPictureGpuAnalyzer(picture).suitableForGpuRasterization(&reason));
REPORTER_ASSERT(reporter, reason);
canvas = recorder.beginRecording(100, 100);
@ -181,7 +183,7 @@ static void test_gpu_veto(skiatest::Reporter* reporter) {
}
picture = recorder.finishRecordingAsPicture();
// A lot of small AA concave paths should be fine for GPU rendering
REPORTER_ASSERT(reporter, picture->suitableForGpuRasterization(nullptr));
REPORTER_ASSERT(reporter, SkPictureGpuAnalyzer(picture).suitableForGpuRasterization());
canvas = recorder.beginRecording(100, 100);
{
@ -203,7 +205,7 @@ static void test_gpu_veto(skiatest::Reporter* reporter) {
}
picture = recorder.finishRecordingAsPicture();
// A lot of large AA concave paths currently render an SkPicture undesireable for GPU rendering
REPORTER_ASSERT(reporter, !picture->suitableForGpuRasterization(nullptr));
REPORTER_ASSERT(reporter, !SkPictureGpuAnalyzer(picture).suitableForGpuRasterization());
canvas = recorder.beginRecording(100, 100);
{
@ -227,7 +229,7 @@ static void test_gpu_veto(skiatest::Reporter* reporter) {
}
picture = recorder.finishRecordingAsPicture();
// hairline stroked AA concave paths are fine for GPU rendering
REPORTER_ASSERT(reporter, picture->suitableForGpuRasterization(nullptr));
REPORTER_ASSERT(reporter, SkPictureGpuAnalyzer(picture).suitableForGpuRasterization());
canvas = recorder.beginRecording(100, 100);
{
@ -243,7 +245,7 @@ static void test_gpu_veto(skiatest::Reporter* reporter) {
}
picture = recorder.finishRecordingAsPicture();
// fast-path dashed effects are fine for GPU rendering ...
REPORTER_ASSERT(reporter, picture->suitableForGpuRasterization(nullptr));
REPORTER_ASSERT(reporter, SkPictureGpuAnalyzer(picture).suitableForGpuRasterization());
canvas = recorder.beginRecording(100, 100);
{
@ -257,18 +259,18 @@ static void test_gpu_veto(skiatest::Reporter* reporter) {
}
picture = recorder.finishRecordingAsPicture();
// ... but only when applied to drawPoint() calls
REPORTER_ASSERT(reporter, !picture->suitableForGpuRasterization(nullptr));
REPORTER_ASSERT(reporter, !SkPictureGpuAnalyzer(picture).suitableForGpuRasterization());
// Nest the previous picture inside a new one.
canvas = recorder.beginRecording(100, 100);
{
canvas->drawPicture(picture.get());
canvas->drawPicture(picture);
}
picture = recorder.finishRecordingAsPicture();
REPORTER_ASSERT(reporter, !picture->suitableForGpuRasterization(nullptr));
REPORTER_ASSERT(reporter, !SkPictureGpuAnalyzer(picture).suitableForGpuRasterization());
}
#endif
#endif // SK_SUPPORT_GPU
static void test_savelayer_extraction(skiatest::Reporter* reporter) {
static const int kWidth = 100;
@ -1346,3 +1348,38 @@ DEF_TEST(Picture_preserveCullRect, r) {
REPORTER_ASSERT(r, deserializedPicture->cullRect().right() == 3);
REPORTER_ASSERT(r, deserializedPicture->cullRect().bottom() == 4);
}
#if SK_SUPPORT_GPU
DEF_TEST(PictureGpuAnalyzer, r) {
SkPictureRecorder recorder;
{
SkCanvas* canvas = recorder.beginRecording(10, 10);
SkPaint paint;
SkScalar intervals [] = { 10, 20 };
paint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 25));
for (int i = 0; i < 50; ++i) {
canvas->drawRect(SkRect::MakeWH(10, 10), paint);
}
}
sk_sp<SkPicture> vetoPicture(recorder.finishRecordingAsPicture());
SkPictureGpuAnalyzer analyzer;
REPORTER_ASSERT(r, analyzer.suitableForGpuRasterization());
analyzer.analyze(vetoPicture.get());
REPORTER_ASSERT(r, !analyzer.suitableForGpuRasterization());
analyzer.reset();
REPORTER_ASSERT(r, analyzer.suitableForGpuRasterization());
recorder.beginRecording(10, 10)->drawPicture(vetoPicture);
sk_sp<SkPicture> nestedVetoPicture(recorder.finishRecordingAsPicture());
analyzer.analyze(nestedVetoPicture.get());
REPORTER_ASSERT(r, !analyzer.suitableForGpuRasterization());
}
#endif // SK_SUPPORT_GPU

View File

@ -7,6 +7,7 @@
#include "SkCommandLineFlags.h"
#include "SkPicture.h"
#include "SkPictureAnalyzer.h"
#include "SkPictureRecorder.h"
#include "SkStream.h"
@ -57,7 +58,7 @@ int tool_main(int argc, char** argv) {
nullptr, 0));
sk_sp<SkPicture> recorded(recorder.finishRecordingAsPicture());
if (recorded->suitableForGpuRasterization(nullptr)) {
if (SkPictureGpuAnalyzer(recorded).suitableForGpuRasterization(nullptr)) {
SkDebugf("suitable\n");
} else {
SkDebugf("unsuitable\n");